ZetCode-GUI-教程-五-

ZetCode GUI 教程(五)

原文:ZetCode

协议:CC BY-NC-SA 4.0

PyGTK 中的小部件 II

原文: http://zetcode.com/gui/pygtk/widgetsII/

在 PyGTK 编程教程的这一部分中,我们将继续介绍 PyGTK 小部件。

Entry

Entry是单行文本输入字段。 该小部件用于输入文本数据。

entry.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example demonstrates the Entry widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Entry")
        self.set_size_request(250, 200)
        self.set_position(gtk.WIN_POS_CENTER)

        fixed = gtk.Fixed()

        self.label = gtk.Label("...")
        fixed.put(self.label, 60, 40)

        entry = gtk.Entry()
        entry.add_events(gtk.gdk.KEY_RELEASE_MASK)
        fixed.put(entry, 60, 100)

        entry.connect("key-release-event", self.on_key_release)

        self.connect("destroy", gtk.main_quit)
        self.add(fixed)
        self.show_all()

    def on_key_release(self, widget, event):
        self.label.set_text(widget.get_text())

PyApp()
gtk.main()

此示例显示了条目小部件和标签。 我们输入的文本将立即显示在标签控件中。

entry = gtk.Entry()

Entry小部件已创建。

entry.connect("key-release-event", self.on_key_release)

如果Entry小部件中的文本被更改,我们将调用on_key_release()方法。

def on_key_release(self, widget, event):
    self.label.set_text(widget.get_text())

我们从Entry小部件获取文本并将其设置为标签。

Entry Widget

图:Entry小部件

HScale

HScale是水平滑块,它使用户可以通过在有限间隔内滑动旋钮来以图形方式选择一个值。 我们的示例将显示音量控制。

hscale.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example demonstrates the HScale widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import sys

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Scale")
        self.set_size_request(260, 150)
        self.set_position(gtk.WIN_POS_CENTER)

        scale = gtk.HScale()
        scale.set_range(0, 100)
        scale.set_increments(1, 10)
        scale.set_digits(0)
        scale.set_size_request(160, 35)
        scale.connect("value-changed", self.on_changed)

        self.load_pixbufs()

        self.image = gtk.Image()
        self.image.set_from_pixbuf(self.mutp)

        fix = gtk.Fixed()
        fix.put(scale, 20, 40)
        fix.put(self.image, 219, 50)

        self.add(fix)

        self.connect("destroy", lambda w: gtk.main_quit())
        self.show_all()

    def load_pixbufs(self):

        try:
            self.mutp = gtk.gdk.pixbuf_new_from_file("mute.png")
            self.minp = gtk.gdk.pixbuf_new_from_file("min.png")
            self.medp = gtk.gdk.pixbuf_new_from_file("med.png")
            self.maxp = gtk.gdk.pixbuf_new_from_file("max.png")

        except Exception, e: 
            print "Error reading Pixbufs"
            print e.message
            sys.exit(1)

    def on_changed(self, widget):
        val = widget.get_value()

        if val == 0:
            self.image.set_from_pixbuf(self.mutp)
        elif val > 0 and val <= 30:
            self.image.set_from_pixbuf(self.minp)
        elif val > 30 and val < 80:
            self.image.set_from_pixbuf(self.medp)
        else: 
            self.image.set_from_pixbuf(self.maxp)

PyApp()
gtk.main()

在上面的示例中,我们有HScaleImage小部件。 通过拖动比例尺,我们可以在Image小部件上更改图像。

scale = gtk.HScale()

HScale小部件已创建。

scale.set_range(0, 100)

我们设置刻度的上下边界。

scale.set_increments(1, 10)

set_increments()方法设置范围的步长和页面大小。

scale.set_digits(0)

我们希望刻度上具有整数值,因此我们将小数位数设置为零。

if val == 0:
    self.image.set_from_pixbuf(self.mutp)
elif val > 0 and val <= 30:
    self.image.set_from_pixbuf(self.minp)
elif val > 30 and val < 80:
    self.image.set_from_pixbuf(self.medp)
else: 
    self.image.set_from_pixbuf(self.maxp)

根据获得的值,我们在图像小部件中更改图片。

HScale Widget

图:HScale小部件

ToggleButton

ToggleButton是具有两种状态的按钮。 已按下但未按下。 通过单击可以在这两种状态之间切换。 在某些情况下此功能非常合适。

togglebuttons.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example demonstrates the ToggleButton widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window):
    def __init__(self):
        super(PyApp, self).__init__()

        self.color = [0, 0, 0]

        self.set_title("ToggleButtons")
        self.resize(350, 240)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)

        red = gtk.ToggleButton("Red")
        red.set_size_request(80, 35)
        red.connect("clicked", self.onred)
        green = gtk.ToggleButton("Green")
        green.set_size_request(80, 35)
        green.connect("clicked", self.ongreen)
        blue = gtk.ToggleButton("Blue")
        blue.set_size_request(80, 35)
        blue.connect("clicked", self.onblue)

        self.darea = gtk.DrawingArea()
        self.darea.set_size_request(150, 150)
        self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))

        fixed = gtk.Fixed()
        fixed.put(red, 30, 30)
        fixed.put(green, 30, 80)
        fixed.put(blue, 30, 130)
        fixed.put(self.darea, 150, 30)

        self.add(fixed)

        self.show_all()

    def onred(self, widget):
        if widget.get_active():
            self.color[0] = 65535
        else: self.color[0] = 0

        self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(self.color[0], 
            self.color[1], self.color[2]))

    def ongreen(self, widget):
        if (widget.get_active()):
            self.color[1] = 65535
        else: self.color[1] = 0

        self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(self.color[0],
            self.color[1], self.color[2]))

    def onblue(self, widget):
        if (widget.get_active()):
            self.color[2] = 65535
        else: self.color[2] = 0

        self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(self.color[0], 
            self.color[1], self.color[2]))

PyApp()
gtk.main()

在我们的示例中,我们显示了三个切换按钮和一个DrawingArea。 我们将区域的背景色设置为黑色。 切换按钮将切换颜色值的红色,绿色和蓝色部分。 背景颜色取决于我们按下的切换按钮。

self.color = [0, 0, 0]

这是将使用切换按钮更新的颜色值。

red = gtk.ToggleButton("Red")
red.set_size_request(80, 35)
red.connect("clicked", self.onred)

ToggleButton小部件已创建。 我们将其大小设置为80x35像素。 每个切换按钮都有其自己的处理器方法。

self.darea = gtk.DrawingArea()
self.darea.set_size_request(150, 150)
self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))

DrawingArea小部件是显示颜色的小部件,由切换按钮混合。 开始时,它显示为黑色。

if widget.get_active():
    self.color[0] = 65535
else: self.color[0] = 0

如果按下切换按钮,我们将相应地更改颜色的 R,G 或 B 部分。

self.darea.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(self.color[0], 
           self.color[1], self.color[2]))

我们更新DrawingArea小部件的颜色。

ToggleButton widget

图:ToggleButton widget

Calendar

我们最终的窗口小部件是Calendar小部件。 它用于处理日期。

calendar.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example demonstrates the Calendar widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Calendar")
        self.set_size_request(300, 270)
        self.set_position(gtk.WIN_POS_CENTER)
        self.set_border_width(2)

        self.label = gtk.Label("...")

        calendar = gtk.Calendar() 
        calendar.connect("day_selected", self.on_day_selected)

        fix = gtk.Fixed()
        fix.put(calendar, 20, 20)
        fix.put(self.label, 40, 230)

        self.add(fix)

        self.connect("destroy", gtk.main_quit)
        self.show_all()

    def on_day_selected(self, widget):
        (year, month, day) = widget.get_date()
        self.label.set_label(str(month) + "/" + str(day) + "/" + str(year))

PyApp()
gtk.main()

我们有Calendar小部件和Label。 从日历中选择的日期显示在标签中。

calendar = gtk.Calendar() 

Calendar小部件已创建。

(year, month, day) = widget.get_date()
self.label.set_label(str(month) + "/" + str(day) + "/" + str(year))

on_day_selected()方法中,我们检索当前选择的日期,并更新标签。

Calendar

图:Calendar

在 PyGTK 教程的这一章中,我们完成了有关 PyGTK 小部件的讨论。

PyGTK 中的高级小部件

原文: http://zetcode.com/gui/pygtk/advancedwidgets/

在 PyGTK 编程教程的这一部分中,我们将介绍 PyGTK 中的一些更高级的小部件。

IconView

IconView是一个小部件,在网格中显示图标列表。

iconview.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example demonstrates the IconView widget.
# It shows the contents of the currently selected
# directory on the disk.
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import os

COL_PATH = 0
COL_PIXBUF = 1
COL_IS_DIRECTORY = 2

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(650, 400)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)
        self.set_title("IconView")

        self.current_directory = '/'

        vbox = gtk.VBox(False, 0);

        toolbar = gtk.Toolbar()
        vbox.pack_start(toolbar, False, False, 0)

        self.upButton = gtk.ToolButton(gtk.STOCK_GO_UP);
        self.upButton.set_is_important(True)
        self.upButton.set_sensitive(False)
        toolbar.insert(self.upButton, -1)

        homeButton = gtk.ToolButton(gtk.STOCK_HOME)
        homeButton.set_is_important(True)
        toolbar.insert(homeButton, -1)

        self.fileIcon = self.get_icon(gtk.STOCK_FILE)
        self.dirIcon = self.get_icon(gtk.STOCK_DIRECTORY)

        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        vbox.pack_start(sw, True, True, 0)

        self.store = self.create_store()
        self.fill_store()

        iconView = gtk.IconView(self.store)
        iconView.set_selection_mode(gtk.SELECTION_MULTIPLE)

        self.upButton.connect("clicked", self.on_up_clicked)
        homeButton.connect("clicked", self.on_home_clicked)

        iconView.set_text_column(COL_PATH)
        iconView.set_pixbuf_column(COL_PIXBUF)

        iconView.connect("item-activated", self.on_item_activated)
        sw.add(iconView)
        iconView.grab_focus()

        self.add(vbox)
        self.show_all()

    def get_icon(self, name):
        theme = gtk.icon_theme_get_default()
        return theme.load_icon(name, 48, 0)

    def create_store(self):
        store = gtk.ListStore(str, gtk.gdk.Pixbuf, bool)
        store.set_sort_column_id(COL_PATH, gtk.SORT_ASCENDING)
        return store

    def fill_store(self):
        self.store.clear()

        if self.current_directory == None:
            return

        for fl in os.listdir(self.current_directory):

            if not fl[0] == '.': 
                if os.path.isdir(os.path.join(self.current_directory, fl)):
                    self.store.append([fl, self.dirIcon, True])
                else:
                    self.store.append([fl, self.fileIcon, False])             

    def on_home_clicked(self, widget):
        self.current_directory = os.path.realpath(os.path.expanduser('~'))
        self.fill_store()
        self.upButton.set_sensitive(True)

    def on_item_activated(self, widget, item):

        model = widget.get_model()
        path = model[item][COL_PATH]
        isDir = model[item][COL_IS_DIRECTORY]

        if not isDir:
            return

        self.current_directory = self.current_directory + os.path.sep + path
        self.fill_store()
        self.upButton.set_sensitive(True)

    def on_up_clicked(self, widget):
        self.current_directory = os.path.dirname(self.current_directory)
        self.fill_store()
        sensitive = True
        if self.current_directory == "/": sensitive = False
        self.upButton.set_sensitive(sensitive)

PyApp()
gtk.main()

本示例显示当前所选目录的图标。 它有一个工具栏和两个按钮。 向上按钮和主页按钮。 我们使用它们来浏览文件系统。

self.current_directory = '/'

current_directory是目录,由IconView小部件显示。

def create_store(self):
    store = gtk.ListStore(str, gtk.gdk.Pixbuf, bool)
    store.set_sort_column_id(COL_PATH, gtk.SORT_ASCENDING)
    return store

create_store()方法创建一个ListStore。 它是IconView小部件中使用的数据模型。 它带有三个参数。 目录名,图标的pixbuf图像和bool变量,指示我们是目录还是文件。

if not fl[0] == '.': 
    if os.path.isdir(os.path.join(self.current_directory, fl)):
        self.store.append([fl, self.dirIcon, True])
    else:
        self.store.append([fl, self.fileIcon, False])     

fill_store()方法中,我们用数据填充列表存储。 在这里,我们找出当前路径中的所有目录。 我们排除以.开头的不可见目录。

def on_home_clicked(self, widget):
    self.current_directory = os.path.realpath(os.path.expanduser('~'))
    self.fill_store()
    self.upButton.set_sensitive(True)

如果单击主页按钮,则主页目录将成为当前目录。 我们重新填充列表存储。 并激活向上按钮。

on_item_activated()方法中,当我们从图标视图小部件中单击一个图标时,我们会对生成的事件做出反应。

model = widget.get_model()
path = model[item][COL_PATH]
isDir = model[item][COL_IS_DIRECTORY]

if not isDir:
    return

我们得到激活项目的路径。 然后我们确定它是目录还是文件。 如果是文件,我们返回。

self.current_directory = self.current_directory + os.path.sep + path
self.fill_store()
self.upButton.set_sensitive(True)

如果是目录,我们将根目录替换为当前路径,重新填充商店,然后使向上按钮敏感。

def on_up_clicked(self, widget):
    self.current_directory = os.path.dirname(self.current_directory)
    self.fill_store()
    sensitive = True
    if self.current_directory == "/": sensitive = False
    self.upButton.set_sensitive(sensitive)

如果单击向上按钮,则将当前目录替换为其父目录。 重新填充列表存储。 如果我们在文件系统的根/目录下,则向上按钮被激活。

IconView

图:IconView

ListView

在下面的示例中,我们使用TreeView小部件显示列表视图。 同样ListStore用于存储数据。

listview.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows a TreeView widget
# in a list view mode
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

actresses = [('jessica alba', 'pomona', '1981'), ('sigourney weaver', 'new york', '1949'),
    ('angelina jolie', 'los angeles', '1975'), ('natalie portman', 'jerusalem', '1981'),
    ('rachel weiss', 'london', '1971'), ('scarlett johansson', 'new york', '1984' )]

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(350, 250)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)
        self.set_title("ListView")

        vbox = gtk.VBox(False, 8)

        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        vbox.pack_start(sw, True, True, 0)

        store = self.create_model()

        treeView = gtk.TreeView(store)
        treeView.connect("row-activated", self.on_activated)
        treeView.set_rules_hint(True)
        sw.add(treeView)

        self.create_columns(treeView)
        self.statusbar = gtk.Statusbar()

        vbox.pack_start(self.statusbar, False, False, 0)

        self.add(vbox)
        self.show_all()

    def create_model(self):
        store = gtk.ListStore(str, str, str)

        for act in actresses:
            store.append([act[0], act[1], act[2]])

        return store

    def create_columns(self, treeView):

        rendererText = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Name", rendererText, text=0)
        column.set_sort_column_id(0)    
        treeView.append_column(column)

        rendererText = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Place", rendererText, text=1)
        column.set_sort_column_id(1)
        treeView.append_column(column)

        rendererText = gtk.CellRendererText()
        column = gtk.TreeViewColumn("Year", rendererText, text=2)
        column.set_sort_column_id(2)
        treeView.append_column(column)

    def on_activated(self, widget, row, col):

        model = widget.get_model()
        text = model[row][0] + ", " + model[row][1] + ", " + model[row][2]
        self.statusbar.push(0, text)

PyApp()
gtk.main()

在我们的示例中,我们在TreeView小部件中显示了六个女演员的列表。 每行分别显示名称,出生地和出生年份。

def create_model(self):
    store = gtk.ListStore(str, str, str)

    for act in actresses:
        store.append([act[0], act[1], act[2]])

    return store

create_model()方法中,我们创建列表存储。 列表存储具有三个参数。 女演员的名字,出生地和出生年份。 这是我们的TreeView小部件的数据模型。

treeView = gtk.TreeView(store)
treeView.connect("row-activated", self.on_activated)
treeView.set_rules_hint(True)

在这里,我们以列表存储为参数创建TreeView小部件。 set_rules_hint()方法更改TreeView小部件中每第二行的背景颜色。

rendererText = gtk.CellRendererText()

column = gtk.TreeViewColumn("Name", rendererText, text=0)
column.set_sort_column_id(0)    
treeView.append_column(column)

create_columns()方法中,我们向TreeView小部件中添加了三列。 上面的代码创建了一个显示女演员姓名的列。 CellRendererText从树模型的第一列检索其文本。 (文本= 0

def on_activated(self, widget, row, col):

    model = widget.get_model()
    text = model[row][0] + ", " + model[row][1] + ", " + model[row][2]
    self.statusbar.push(0, text)

如果双击某个项目,则会在状态栏中显示整行。

ListView

图:ListView

TreeView

在本章的最后一个示例中,我们使用TreeView小部件显示分层的数据树。

tree.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows a TreeView widget
# in a tree view mode
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(400, 300)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)
        self.set_title("Tree")

        tree = gtk.TreeView()

        languages = gtk.TreeViewColumn()
        languages.set_title("Programming languages")

        cell = gtk.CellRendererText()
        languages.pack_start(cell, True)
        languages.add_attribute(cell, "text", 0)

        treestore = gtk.TreeStore(str)

        it = treestore.append(None, ["Scripting languages"])
        treestore.append(it, ["Python"])
        treestore.append(it, ["PHP"])
        treestore.append(it, ["Perl"])
        treestore.append(it, ["Ruby"])

        it = treestore.append(None, ["Compiling languages"])
        treestore.append(it, ["C#"])
        treestore.append(it, ["C++"])
        treestore.append(it, ["C"])
        treestore.append(it, ["Java"])

        tree.append_column(languages)
        tree.set_model(treestore)

        self.add(tree)
        self.show_all()

PyApp()
gtk.main()

这次我们使用TreeView小部件显示分层数据。

tree = gtk.TreeView()

TreeView小部件已创建。

languages = gtk.TreeViewColumn()
languages.set_title("Programming languages")

它有一列名为"Programming languages"

cell = gtk.CellRendererText()
languages.pack_start(cell, True)
languages.add_attribute(cell, "text", 0)

我们在TreeView小部件中显示文本数据。

treestore = gtk.TreeStore(str)

要存储数据,我们使用TreeStore对象。

it = treestore.append(None, ["Scripting languages"])
treestore.append(it, ["Python"])
treestore.append(it, ["PHP"])

我们将数据附加到树上。 TreeIter对象用于访问一行中的数据。

tree.append_column(languages)

一列被附加到树上。

tree.set_model(treestore)

最后,我们为树小部件设置数据模型。

Tree

图:Tree

在 PyGTK 编程教程的这一章中,我们讨论的是高级 PyGTK 小部件。

PyGTK 中的对话框

原文: http://zetcode.com/gui/pygtk/dialogs/

在 PyGTK 编程教程的这一部分中,我们将介绍对话框。

对话框窗口或对话框是大多数现代 GUI 应用必不可少的部分。 对话被定义为两个或更多人之间的对话。 在计算机应用中,对话框是一个窗口,用于与应用“对话”。 反之亦然。 对话框用于输入数据,修改数据,更改应用设置等。对话框是用户与计算机程序之间进行通信的重要手段。

MessageDialog

消息对话框是方便的对话框,可向应用的用户提供消息。 该消息包含文本和图像数据。

messages.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows message
# dialogs
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(250, 100)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)
        self.set_title("Message dialogs")

        table = gtk.Table(2, 2, True);

        info = gtk.Button("Information")
        warn = gtk.Button("Warning")
        ques = gtk.Button("Question")
        erro = gtk.Button("Error")

        info.connect("clicked", self.on_info)
        warn.connect("clicked", self.on_warn)
        ques.connect("clicked", self.on_ques)
        erro.connect("clicked", self.on_erro)

        table.attach(info, 0, 1, 0, 1)
        table.attach(warn, 1, 2, 0, 1)
        table.attach(ques, 0, 1, 1, 2)
        table.attach(erro, 1, 2, 1, 2)

        self.add(table)
        self.show_all()

    def on_info(self, widget):
        md = gtk.MessageDialog(self, 
            gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, 
            gtk.BUTTONS_CLOSE, "Download completed")
        md.run()
        md.destroy()

    def on_erro(self, widget):
        md = gtk.MessageDialog(self, 
            gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, 
            gtk.BUTTONS_CLOSE, "Error loading file")
        md.run()
        md.destroy()

    def on_ques(self, widget):
        md = gtk.MessageDialog(self, 
            gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, 
            gtk.BUTTONS_CLOSE, "Are you sure to quit?")
        md.run()
        md.destroy()

    def on_warn(self, widget):
        md = gtk.MessageDialog(self, 
            gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, 
            gtk.BUTTONS_CLOSE, "Unallowed operation")
        md.run()
        md.destroy()

PyApp()
gtk.main()

在我们的示例中,我们将显示四种消息对话框。 信息,警告,问题和错误消息对话框。

info = gtk.Button("Information")
warn = gtk.Button("Warning")
ques = gtk.Button("Question")
erro = gtk.Button("Error")

我们有四个按钮。 这些按钮中的每个按钮都会显示不同类型的消息对话框。

md = gtk.MessageDialog(self, 
    gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, 
        gtk.BUTTONS_CLOSE, "Download completed")
md.run()
md.destroy()

如果单击信息按钮,将显示“信息”对话框。 MESSAGE_INFO指定对话框的类型。 BUTTONS_CLOSE指定要在对话框中显示的按钮。 最后一个参数是显示的消息。 该对话框使用run()方法显示。 程序员还必须调用destroy()hide()方法。

Information message dialog

Warning message dialog

Question message dialog

Error message dialog

AboutDialog

AboutDialog显示有关应用的信息。 AboutDialog可以显示徽标,应用名称,版本,版权,网站或许可证信息。 也有可能对作者,文档撰写者,翻译者和艺术家予以赞扬。

aboutdialog.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example demonstrates the
# AboutDialog dialog
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()
        self.set_size_request(300, 150)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)
        self.set_title("About battery")

        button = gtk.Button("About")
        button.set_size_request(80, 30)
        button.connect("clicked", self.on_clicked)

        fix = gtk.Fixed()
        fix.put(button, 20, 20)

        self.add(fix)
        self.show_all()

    def on_clicked(self, widget):
        about = gtk.AboutDialog()
        about.set_program_name("Battery")
        about.set_version("0.1")
        about.set_copyright("(c) Jan Bodnar")
        about.set_comments("Battery is a simple tool for battery checking")
        about.set_website("http://www.zetcode.com")
        about.set_logo(gtk.gdk.pixbuf_new_from_file("battery.png"))
        about.run()
        about.destroy()

PyApp()
gtk.main()

该代码示例使用具有某些功能的AboutDialog

about = gtk.AboutDialog()

我们创建一个AboutDialog

about = gtk.AboutDialog()
about.set_program_name("Battery")
about.set_version("0.1")
about.set_copyright("(c) Jan Bodnar")

我们指定名称,版本和版权。

about.set_logo(gtk.gdk.pixbuf_new_from_file("battery.png"))

此行创建徽标。

AboutDialog

图:AboutDialog

FontSelectionDialog

FontSelectionDialog是用于选择字体的对话框。 它通常用于进行一些文本编辑或格式化的应用中。

fontdialog.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example works with the
# FontSelection dialog
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

class PyApp(gtk.Window): 
    def __init__(self):
        gtk.Window.__init__(self)
        self.set_size_request(300, 150)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)
        self.set_title("Font Selection Dialog")

        self.label = gtk.Label("The only victory over love is flight.")
        button = gtk.Button("Select font")
        button.connect("clicked", self.on_clicked)

        fix = gtk.Fixed()
        fix.put(button, 100, 30)
        fix.put(self.label, 30, 90)
        self.add(fix)

        self.show_all()

    def on_clicked(self, widget):
        fdia = gtk.FontSelectionDialog("Select font name")
        response = fdia.run()

        if response == gtk.RESPONSE_OK:
            font_desc = pango.FontDescription(fdia.get_font_name())
            if font_desc:
                self.label.modify_font(font_desc)

        fdia.destroy()

PyApp()
gtk.main()

在代码示例中,我们有一个按钮和一个标签。 单击按钮显示FontSelectionDialog

fdia = gtk.FontSelectionDialog("Select font name")

我们创建了FontSelectionDialog.

if response == gtk.RESPONSE_OK:
    font_desc = pango.FontDescription(fdia.get_font_name())
    if font_desc:
        self.label.modify_font(font_desc)

如果单击“确定”按钮,则标签小部件的字体将更改为我们在对话框中选择的字体。

FontSelectionDialog

图:FontSelectionDialog

ColorSelectionDialog

ColorSelectionDialog是用于选择颜色的对话框。

colordialog.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example works with the
# ColorSelection dialog
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(300, 150)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)
        self.set_title("Color Selection Dialog")

        self.label = gtk.Label("The only victory over love is flight.")
        button = gtk.Button("Select color")
        button.connect("clicked", self.on_clicked)

        fix = gtk.Fixed()
        fix.put(button, 100, 30)
        fix.put(self.label, 30, 90)
        self.add(fix)

        self.show_all()

    def on_clicked(self, widget):
        cdia = gtk.ColorSelectionDialog("Select color")
        response = cdia.run()

        if response == gtk.RESPONSE_OK:
            colorsel = cdia.colorsel
            color = colorsel.get_current_color()
            self.label.modify_fg(gtk.STATE_NORMAL, color)

        cdia.destroy()

PyApp()
gtk.main()

该示例与上一个示例非常相似。 这次我们更改标签的颜色。

cdia = gtk.ColorSelectionDialog("Select color")

我们创建ColorSelectionDialog

if response == gtk.RESPONSE_OK:
    colorsel = cdia.colorsel
    color = colorsel.get_current_color()
    self.label.modify_fg(gtk.STATE_NORMAL, color)

如果用户按下 OK,我们将获得颜色并修改标签的颜色。

ColorSelectionDialog

图:颜色 electionDialog

在 PyGTK 编程教程的这一部分中,我们使用了 PyGTK 内置对话框。

Pango

原文: http://zetcode.com/gui/pygtk/pango/

在 PyGTK 编程教程的这一部分中,我们将探索 Pango 库。

Pango 是一个免费的开源计算库,可高质量呈现国际化文本。 可以使用不同的字体后端,从而允许跨平台支持。 (维基百科)

Pango 提供了用于GdkGtk的高级字体和文本处理。

简单的例子

在第一个示例中,我们展示了如何更改标签小部件的字体。

quotes.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows how to modify
# the font of a label
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

quotes = """Excess of joy is harder to bear than any amount of sorrow.
The more one judges, the less one loves.
There is no such thing as a great talent without great will power. 
"""

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.connect("destroy", gtk.main_quit)
        self.set_title("Quotes")

        label = gtk.Label(quotes)
        gtk.gdk.beep()

        fontdesc = pango.FontDescription("Purisa 10")
        label.modify_font(fontdesc)

        fix = gtk.Fixed()

        fix.put(label, 5, 5)

        self.add(fix)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

PyApp()
gtk.main()

在上面的代码示例中,我们有一个带有三个引号的标签小部件。 我们将其字体更改为 Purisa 10。

 quotes = """Excess of joy is harder to bear than any amount of sorrow.
 The more one judges, the less one loves.
 There is no such thing as a great talent without great will power. 
"""

这是要在标签中显示的文本。

fontdesc = pango.FontDescription("Purisa 10")

FontDescription用于指定字体的特征。

label.modify_font(fontdesc)

我们将标签小部件的字体更改为 Purisa 10。

Quotations

图:Quotations

系统字体

下一个代码示例显示TreeView小部件中的所有可用字体。

systemfonts.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example lists all available
# fonts on a system in a TreeView widget
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_size_request(350, 250)
        self.set_border_width(8)
        self.connect("destroy", gtk.main_quit)
        self.set_title("System fonts")

        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        context = self.create_pango_context()
        self.fam = context.list_families()

        store = self.create_model()

        treeView = gtk.TreeView(store)
        treeView.set_rules_hint(True)
        sw.add(treeView)

        self.create_column(treeView)

        self.add(sw)

        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

    def create_column(self, treeView):
        rendererText = gtk.CellRendererText()
        column = gtk.TreeViewColumn("FontName", rendererText, text=0)
        column.set_sort_column_id(0)    
        treeView.append_column(column)

    def create_model(self):
        store = gtk.ListStore(str)

        for ff in self.fam:
            store.append([ff.get_name()])

        return store

PyApp()
gtk.main()

该代码示例显示了系统上所有可用的字体。

context = self.create_pango_context()

此代码行创建一个 pango 上下文对象。 它包含有关文本渲染过程的全局信息。

self.fam = context.list_families()

从上下文对象中,我们检索所有可用的字体系列。

for ff in self.fam:
    store.append([ff.get_name()])

TreeView小部件的模型创建期间,我们从字体家族数组中获取所有字体名称,并将它们放入列表存储中。

System fonts

图:系统字体

Unicode

Pango 用于处理国际化文本。

unicode.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

# ZetCode PyGTK tutorial 
#
# This example displays text
# in azbuka
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

obj = unicode(u'''Фёдор Михайлович Достоевский родился 30 октября (11 ноября)
1821 года в Москве. Был вторым из 7 детей. Отец, Михаил Андреевич, 
работал вгоспитале для бедных. Мать, Мария Фёдоровна 
(в девичестве Нечаева), происходила из купеческого рода.''')

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.connect("destroy", gtk.main_quit)
        self.set_title("Unicode")

        label = gtk.Label(obj.encode('utf-8'))

        fontdesc = pango.FontDescription("Purisa 10")
        label.modify_font(fontdesc)

        fix = gtk.Fixed()

        fix.put(label, 5, 5)

        self.add(fix)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

PyApp()
gtk.main()

我们在西里尔字母中显示一些文本。

# -*- coding: utf-8 -*-

为了直接在源代码中使用国际化文本,我们必须提供此魔术注释。 请注意,它必须在第一行或第二行上。

 obj = unicode(u'''Фёдор Михайлович Достоевский родился 30 октября (11 ноября)
1821 года в Москве. Был вторым из 7 детей. Отец, Михаил Андреевич, 
работал вгоспитале для бедных. Мать, Мария Фёдоровна 
(в девичестве Нечаева), происходила из купеческого рода.''')

这是阿兹布卡语中的文字。

Label label = new Label(text);

我们将编码的文本放入标签中。

Unicode

图:Unicode

属性

Pango 属性是适用于一段文字的属性。

attributes.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# In this program we work with
# pango attributes
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

text = "Valour fate kinship darkness"

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.connect("destroy", gtk.main_quit)
        self.set_title("Attributes")

        label = gtk.Label(text)

        attr = pango.AttrList()

        fg_color = pango.AttrForeground(65535, 0, 0, 0, 6)
        underline = pango.AttrUnderline(pango.UNDERLINE_DOUBLE, 7, 11)
        bg_color = pango.AttrBackground(40000, 40000, 40000, 12, 19)
        strike = pango.AttrStrikethrough(True, 20, 29)
        size = pango.AttrSize(30000, 0, -1)

        attr.insert(fg_color)
        attr.insert(underline)
        attr.insert(bg_color)
        attr.insert(size)
        attr.insert(strike)

        label.set_attributes(attr)

        fix = gtk.Fixed()

        fix.put(label, 5, 5)

        self.add(fix)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

PyApp()
gtk.main()

在代码示例中,我们显示了应用于文本的四个不同属性。

attr = pango.AttrList()

Pango 属性列表是用于保存属性的对象。

fg_color = pango.AttrForeground(65535, 0, 0, 0, 6)

在这里,我们创建一个属性,该属性将以红色呈现文本。 前三个参数是颜色的 R,G,B 值。 最后两个参数是文本的开始和结束索引,我们将其应用于此属性。

label.set_attributes(attr)

我们设置标签的属性列表。

Pango attributes

图:Pango 属性

在 PyGTK 编程库的这一章中,我们使用了 pango 库。

Pango II

原文: http://zetcode.com/gui/pygtk/pangoII/

在 PyGTK 编程教程的这一部分中,我们将继续探索 Pango 库。

动画文字

下面的示例在窗口上显示动画文本。

animation.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows animated text
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import glib
import pango
import math

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.connect("destroy", gtk.main_quit)
        glib.timeout_add(160, self.on_timer)

        self.count = 1

        self.set_border_width(10)
        self.set_title("ZetCode")

        self.label = gtk.Label("ZetCode")

        fontdesc = pango.FontDescription("Serif Bold 30")
        self.label.modify_font(fontdesc)

        vbox = gtk.VBox(False, 0)
        vbox.add(self.label)

        self.add(vbox)
        self.set_size_request(300, 250)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

    def on_timer(self):
        attr = pango.AttrList()
        self.count = self.count + 1

        for i in range(7):
            r = pango.AttrRise(int(math.sin(self.count+i)*20)*pango.SCALE, i, i+1)
            attr.insert(r)

        self.label.set_attributes(attr)
        return True

PyApp()
gtk.main()

在上面的代码示例中,标签小部件中有一个文本。 通过不断更改其 pango 属性,可以对文本进行动画处理。

self.label = gtk.Label("ZetCode")

fontdesc = pango.FontDescription("Serif Bold 30")
self.label.modify_font(fontdesc)

我们创建标签小部件并修改其字体。 我们选择较大的文本以提高可见性。

vbox = gtk.VBox(False, 0)
vbox.add(self.label)

我们将标签放入垂直框中。 这将标签居中在窗口上。

动画在on_timer()方法内部执行。

for i in range(7):
    r = pango.AttrRise(int(math.sin(self.count+i)*20)*pango.SCALE, i, i+1)
    attr.insert(r)

我们的文字中有七个字符。 我们会定期更改每个角色的 pango AttrRise属性。 上升基于三角正弦函数。 文本移动遵循在笛卡尔图上绘制的正弦函数。

另请注意pango.SCALE常数。 Pango 库有自己的单元。 它们与小部件用来绘制图形或文本的方式不同。 我们必须用这个常数乘数字。

Animated text

图:动画文本

使用标记语言

我们可以使用内置的标记语言来更改文本的属性。

markup.py


#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example uses markup language
# to change attributes of the text
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

quote = "<span foreground='blue' size='19000'>The only victory over love is flight</span>"

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Markup")
        self.set_border_width(5)
        self.connect("destroy", gtk.main_quit)

        label = gtk.Label()
        label.set_markup(quote)

        vbox = gtk.VBox(False, 0)
        vbox.add(label)

        self.add(vbox)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

PyApp()
gtk.main()

在代码示例中,我们有一个标签。 我们使用标记语言更改其文本属性。

quote = "<span foreground='blue' size='19000'>The only victory over love is flight</span>"

这是带有标记语言的文本。

label = gtk.Label()
label.set_markup(quote)

我们创建标签小部件并为其设置标记文本。

Using markup

图:使用标记

Pango 布局

Pango 布局是一个对象,代表带有属性的文本段落。

layout.py


#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This example shows pango Layout
# in action
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import pango

lyrics = """Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
You say why did you do it with him today?
and sniff me out like I was Tanqueray

cause you're my fella, my guy
hand me your stella and fly
by the time I'm out the door
you tear men down like Roger Moore

I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good"""

class Area(gtk.DrawingArea):
    def __init__(self):
        super(Area, self).__init__()
        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(16400, 16400, 16440))
        self.connect("expose_event", self.expose)

    def expose(self, widget, event):

        gc = self.get_style().fg_gc[gtk.STATE_NORMAL]
        font_desc = pango.FontDescription('Sans 10')

        layout = self.create_pango_layout(lyrics)
        width, height = self.get_size_request()

        attr = pango.AttrList()

        fg_color = pango.AttrForeground(60535, 60535, 60535, 0, -1)
        attr.insert(fg_color)

        layout.set_width(pango.SCALE * self.allocation.width)
        layout.set_spacing(pango.SCALE * 3)
        layout.set_alignment(pango.ALIGN_CENTER)
        layout.set_font_description(font_desc)
        layout.set_attributes(attr)

        self.window.draw_layout(gc, 0, 5, layout)

class PyApp(gtk.Window): 
    def __init__(self):
        super(PyApp, self).__init__()

        self.connect("destroy", gtk.main_quit)
        self.set_title("You know I'm no Good")

        self.add(Area())
        self.set_size_request(300, 300)
        self.set_position(gtk.WIN_POS_CENTER)
        self.show_all()

PyApp()
gtk.main()

在前面的示例中,我们正在修改现有小部件中的文本。 现在,我们将使用DrawingArea小部件上的 pango 布局绘制文本。 我们将使用Gdk绘图工具进行绘图。

gc = self.get_style().fg_gc[gtk.STATE_NORMAL]

我们得到了绘图区域小部件的图形顶点。

layout = self.create_pango_layout(lyrics)

在这里创建 pango 布局对象。

layout.set_width(pango.SCALE * self.allocation.width)
layout.set_spacing(pango.SCALE * 3)
layout.set_alignment(pango.ALIGN_CENTER)
layout.set_font_description(font_desc)
layout.set_attributes(attr)

我们修改布局的宽度,间距,对齐方式,字体并设置文本属性。

self.window.draw_layout(gc, 0, 5, layout)

布局正在窗口上绘制。

Layout

图:布局

在 PyGTK 编程库的这一章中,我们进一步使用了 pango 库。

PyGTK 中的 Cario 绘图

原文: http://zetcode.com/gui/pygtk/drawing/

在 PyGTK 编程教程的这一部分中,我们将使用 Cairo 库进行一些绘制。

Cairo 是用于创建 2D 矢量图形的库。 我们可以使用它来绘制自己的小部件,图表以及各种效果或动画。

简单绘图

描边操作绘制形状的轮廓,填充操作填充形状的内部。 接下来,我们将演示这两个操作。

simpledrawing.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This code example draws a circle
# using the cairo library
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import math

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Simple drawing")
        self.resize(230, 150)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_line_width(9)
        cr.set_source_rgb(0.7, 0.2, 0.0)

        w = self.allocation.width
        h = self.allocation.height

        cr.translate(w/2, h/2)
        cr.arc(0, 0, 50, 0, 2*math.pi)
        cr.stroke_preserve()

        cr.set_source_rgb(0.3, 0.4, 0.6)
        cr.fill()

PyApp()
gtk.main()

在我们的示例中,我们将绘制一个圆并将其用纯色绘制。

darea = gtk.DrawingArea()

我们将在DrawingArea小部件上进行绘制操作。

darea.connect("expose-event", self.expose)

我们都使用作为expose-event信号处理器的方法进行绘制。

cr = widget.window.cairo_create()

我们从绘图区域的gdk.Window创建 cairo 上下文对象。 上下文是用于在所有Drawable对象上绘制的对象。

cr.set_line_width(9)

我们将线条的宽度设置为 9 像素。

cr.set_source_rgb(0.7, 0.2, 0.0)

我们将颜色设置为深红色。

w = self.allocation.width
h = self.allocation.height

cr.translate(w/2, h/2)

我们得到绘图区域的宽度和高度。 我们将原点移动到窗口的中间。

cr.arc(0, 0, 50, 0, 2*math.pi)
cr.stroke_preserve()

我们绘制一个圆形的外部形状。 红色。 stroke_preserve()根据当前的线宽,线连接,线帽和笔划线设置描边当前路径。 与stroke()不同,它在 cairo 上下文中保留路径。

cr.set_source_rgb(0.3, 0.4, 0.6)
cr.fill()

这会用一些蓝色填充圆圈的内部。

Simple drawing

图:简单 drawing

基本形状

下一个示例将一些基本形状绘制到窗口上。

basicshapes.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This code example draws basic shapes
# with the cairo library
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import math

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Basic shapes")
        self.set_size_request(390, 240)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()
        cr.set_source_rgb(0.6, 0.6, 0.6)

        cr.rectangle(20, 20, 120, 80)
        cr.rectangle(180, 20, 80, 80)
        cr.fill()

        cr.arc(330, 60, 40, 0, 2*math.pi)
        cr.fill()

        cr.arc(90, 160, 40, math.pi/4, math.pi)
        cr.fill()

        cr.translate(220, 180)
        cr.scale(1, 0.7)
        cr.arc(0, 0, 50, 0, 2*math.pi)
        cr.fill()

PyApp()
gtk.main()

在此示例中,我们将创建一个矩形,一个正方形,一个圆形,一个弧形和一个椭圆形。

cr.rectangle(20, 20, 120, 80)
cr.rectangle(180, 20, 80, 80)
cr.fill()

这些线绘制一个矩形和一个正方形。

cr.arc(330, 60, 40, 0, 2*math.pi)
cr.fill()

此处arc()方法绘制一个完整的圆。

cr.scale(1, 0.7)
cr.arc(0, 0, 50, 0, 2*math.pi)
cr.fill()

如果要绘制椭圆形,请先进行一些缩放。 在这里scale()方法缩小 y 轴。

Basic shapes

图:基本形状

色彩

颜色是代表红色,绿色和蓝色(RGB)强度值的组合的对象。 Cario 有效 RGB 值在 0 到 1 的范围内。

colors.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program shows how to work
# with colors in cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Colors")
        self.resize(360, 100)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_source_rgb(0.2, 0.23, 0.9)
        cr.rectangle(10, 15, 90, 60)
        cr.fill()

        cr.set_source_rgb(0.9, 0.1, 0.1)
        cr.rectangle(130, 15, 90, 60)
        cr.fill()

        cr.set_source_rgb(0.4, 0.9, 0.4)
        cr.rectangle(250, 15, 90, 60)
        cr.fill()

PyApp()
gtk.main()

我们用三种不同的颜色绘制三个矩形。

cr.set_source_rgb(0.2, 0.23, 0.9)

set_source_rgb()方法为 Cario 上下文设置颜色。 该方法的三个参数是颜色强度值。

cr.rectangle(10, 15, 90, 60)
cr.fill()

我们创建一个矩形形状,并用先前指定的颜色填充它。

Colors

图:颜色

透明矩形

透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。

在计算机图形学中,我们可以使用 alpha 合成来实现透明效果。 Alpha 合成是将图像与背景组合以创建部分透明外观的过程。 合成过程使用 Alpha 通道。 (wikipedia.org,answers.com)

transparentrectangles.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program shows transparent
# rectangles using cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Transparent rectangles")
        self.resize(590, 90)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        for i in range(1, 11):
            cr.set_source_rgba(0, 0, 1, i*0.1)
            cr.rectangle(50*i, 20, 40, 40)
            cr.fill()

PyApp()
gtk.main()

在示例中,我们将绘制十个具有不同透明度级别的矩形。

cr.set_source_rgba(0, 0, 1, i*0.1)

set_source_rgba()方法的最后一个参数是 alpha 透明度。

Transparent rectangles

图:透明矩形

灵魂伴侣

在下一个示例中,我们在窗口上绘制一些文本。

soulmate.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program draws text
# using cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import cairo

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Soulmate")
        self.set_size_request(370, 240)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_source_rgb(0.1, 0.1, 0.1)

        cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL, 
            cairo.FONT_WEIGHT_NORMAL)
        cr.set_font_size(13)

        cr.move_to(20, 30)
        cr.show_text("Most relationships seem so transitory")
        cr.move_to(20, 60)
        cr.show_text("They're all good but not the permanent one")
        cr.move_to(20, 120)
        cr.show_text("Who doesn't long for someone to hold")
        cr.move_to(20, 150)
        cr.show_text("Who knows how to love without being told")
        cr.move_to(20, 180)
        cr.show_text("Somebody tell me why I'm on my own")
        cr.move_to(20, 210)
        cr.show_text("If there's a soulmate for everyone")

PyApp()
gtk.main()

我们显示 Natasha Bedingfields Soulmate 歌曲的部分歌词。

cr.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL, 
    cairo.FONT_WEIGHT_NORMAL)

在这里,我们指定使用的字体。

cr.set_font_size(13)

我们指定字体的大小。

cr.move_to(20, 30)

我们移动到要绘制文本的位置。

cr.show_text("Most relationships seem so transitory")

show_text()方法将文本绘制到窗口上。

Soulmate

图:灵魂伴侣

在 PyGTK 编程库的这一章中,我们使用 Cairo 图形库进行绘制。

Cario 绘图 II

原文: http://zetcode.com/gui/pygtk/drawingII/

在 PyGTK 编程教程的这一部分中,我们将继续使用 Cairo 库进行绘制。

甜甜圈

在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。

donut.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program creates a donut
# with cairo library
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import math

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Donut")
        self.set_size_request(350, 250)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_line_width(0.5)

        w = self.allocation.width
        h = self.allocation.height

        cr.translate(w/2, h/2)
        cr.arc(0, 0, 120, 0, 2*math.pi)
        cr.stroke()

        for i in range(36):
            cr.save()
            cr.rotate(i*math.pi/36)
            cr.scale(0.3, 1)
            cr.arc(0, 0, 120, 0, 2*math.pi)
            cr.restore()
            cr.stroke()

PyApp()
gtk.main()

在此示例中,我们创建一个甜甜圈。 形状类似于曲奇,因此得名“甜甜圈”。

cr.translate(w/2, h/2)
cr.arc(0, 0, 120, 0, 2*math.pi)
cr.stroke()

刚开始时有一个椭圆。

for i in range(36):
    cr.save()
    cr.rotate(i*math.pi/36)
    cr.scale(0.3, 1)
    cr.arc(0, 0, 120, 0, 2*math.pi)
    cr.restore()
    cr.stroke()

旋转几圈后,有一个甜甜圈。 我们使用save()restore()方法将每个旋转和缩放操作彼此隔离。

Donut

图:多纳圈

渐变

在计算机图形学中,渐变是从浅到深或从一种颜色到另一种颜色的阴影的平滑混合。 在 2D 绘图程序和绘图程序中,渐变用于创建彩色背景和特殊效果以及模拟灯光和阴影。 (answers.com)

gradients.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program works with
# gradients in cairo
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import cairo

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Gradients")
        self.set_size_request(340, 390)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()
        lg1 = cairo.LinearGradient(0.0, 0.0, 350.0, 350.0)

        count = 1

        i = 0.1    
        while i < 1.0: 
            if count % 2:
                lg1.add_color_stop_rgba(i, 0, 0, 0, 1)
            else:
                lg1.add_color_stop_rgba(i, 1, 0, 0, 1)
            i = i + 0.1
            count = count + 1      

        cr.rectangle(20, 20, 300, 100)
        cr.set_source(lg1)
        cr.fill()

        lg2 = cairo.LinearGradient(0.0, 0.0, 350.0, 0)

        count = 1

        i = 0.05    
        while i < 0.95: 
            if count % 2:
                lg2.add_color_stop_rgba(i, 0, 0, 0, 1)
            else:
                lg2.add_color_stop_rgba(i, 0, 0, 1, 1)
            i = i + 0.025
            count = count + 1        

        cr.rectangle(20, 140, 300, 100)
        cr.set_source(lg2)
        cr.fill()

        lg3 = cairo.LinearGradient(20.0, 260.0,  20.0, 360.0)
        lg3.add_color_stop_rgba(0.1, 0, 0, 0, 1) 
        lg3.add_color_stop_rgba(0.5, 1, 1, 0, 1) 
        lg3.add_color_stop_rgba(0.9, 0, 0, 0, 1) 

        cr.rectangle(20, 260, 300, 100)
        cr.set_source(lg3)
        cr.fill()

PyApp()
gtk.main()

在我们的示例中,我们绘制了三个具有三个不同渐变的矩形。

lg1 = cairo.LinearGradient(0.0, 0.0, 350.0, 350.0)

在这里,我们创建一个线性渐变图案。 参数指定直线,沿着该直线绘制渐变。 在我们的情况下,这是一条垂直线。

lg3 = cairo.LinearGradient(20.0, 260.0,  20.0, 360.0)
lg3.add_color_stop_rgba(0.1, 0, 0, 0, 1) 
lg3.add_color_stop_rgba(0.5, 1, 1, 0, 1) 
lg3.add_color_stop_rgba(0.9, 0, 0, 0, 1) 

我们定义色标以产生渐变图案。 在这种情况下,渐变是黑色和黄色的混合。 通过添加两个黑色和一个黄色色标,我们创建了一个水平渐变图案。 这些停止实际上是什么意思? 在我们的情况下,我们从黑色开始,该颜色将以大小的 1/10 停止。 然后,我们开始逐渐涂成黄色,最终达到形状的中心。 黄色停在大小的 9/10,我们再次开始用黑色绘图,直到结束。

Gradients

图:渐变

泡泡

在以下示例中,我们创建一个粉扑效果。 该示例将显示一个不断增长的居中文本,该文本将从某个点逐渐淡出。 这是一个非常常见的效果,您经常可以在 Flash 动画中看到它。

puff.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program creates a puff
# effect 
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import glib
import cairo

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Puff")
        self.resize(350, 200)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        self.darea = gtk.DrawingArea()
        self.darea.connect("expose-event", self.expose)
        self.add(self.darea)

        self.timer = True
        self.alpha = 1.0
        self.size = 1.0

        glib.timeout_add(14, self.on_timer)

        self.show_all()

    def on_timer(self):
        if not self.timer: return False

        self.darea.queue_draw()
        return True

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        w = self.allocation.width
        h = self.allocation.height

        cr.set_source_rgb(0.5, 0, 0)
        cr.paint()

        cr.select_font_face("Courier", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)

        self.size = self.size + 0.8

        if self.size > 20:
            self.alpha = self.alpha - 0.01

        cr.set_font_size(self.size)
        cr.set_source_rgb(1, 1, 1)

        (x, y, width, height, dx, dy) = cr.text_extents("ZetCode")

        cr.move_to(w/2 - width/2, h/2)
        cr.text_path("ZetCode")
        cr.clip()
        cr.stroke()
        cr.paint_with_alpha(self.alpha)

        if self.alpha <= 0:
            self.timer = False

PyApp()
gtk.main()

该示例在窗口上创建一个逐渐增长和褪色的文本。

glib.timeout_add(14, self.on_timer)

每隔 14 毫秒调用一次on_timer()方法。

def on_timer(self):
    if not self.timer: return False

    self.darea.queue_draw()
    return True     

on_timer()方法中,我们在绘图区域上调用queue_draw()方法,该方法会触发曝光信号。

cr.set_source_rgb(0.5, 0, 0)
cr.paint()

我们将背景色设置为深红色。

self.size = self.size + 0.8

每个周期,字体大小将增加 0.8 个单位。

if self.size > 20:
    self.alpha = self.alpha - 0.01

字体大小大于 20 后开始淡出。

(x, y, width, height, dx, dy) = cr.text_extents("ZetCode")

我们得到了文本指标。

cr.move_to(w/2 - width/2, h/2)

我们使用文本指标将文本放在窗口的中心。

cr.text_path("ZetCode")
cr.clip()

我们获取文本的路径,并为其设置当前的片段区域。

cr.stroke()
cr.paint_with_alpha(self.alpha)

我们绘制当前路径并考虑 alpha 值。

Puff

图:粉扑

反射

在下一个示例中,我们显示反射图像。 这种美丽的效果使人产生幻觉,好像图像在水中被反射一样。

reflection.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

# ZetCode PyGTK tutorial 
#
# This program creates an
# image reflection
#
# author: Jan Bodnar
# website: zetcode.com 
# last edited: April 2011

import gtk
import cairo
import sys

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Reflection")
        self.resize(300, 350)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        darea = gtk.DrawingArea()
        darea.connect("expose-event", self.expose)
        self.add(darea)

        try:
            self.surface = cairo.ImageSurface.create_from_png("slanec.png")
        except Exception, e:
            print e.message
            sys.exit(1)

        self.imageWidth = self.surface.get_width()
        self.imageHeight = self.surface.get_height()
        self.gap = 40
        self.border = 20

        self.show_all()

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        w = self.allocation.width
        h = self.allocation.height

        lg = cairo.LinearGradient(w/2, 0, w/2, h*3)
        lg.add_color_stop_rgba(0, 0, 0, 0, 1)
        lg.add_color_stop_rgba(h, 0.2, 0.2, 0.2, 1)

        cr.set_source(lg)
        cr.paint()

        cr.set_source_surface(self.surface, self.border, self.border)
        cr.paint()

        alpha = 0.7
        step = 1.0 / self.imageHeight

        cr.translate(0, 2 * self.imageHeight + self.gap)
        cr.scale(1, -1)

        i = 0

        while(i < self.imageHeight):

            cr.rectangle(self.border, self.imageHeight-i, self.imageWidth, 1)

            i = i + 1

            cr.save()
            cr.clip()
            cr.set_source_surface(self.surface, self.border, self.border)
            alpha = alpha - step
            cr.paint_with_alpha(alpha)
            cr.restore()

PyApp()
gtk.main()

该示例显示了一个反射的城堡。

lg = cairo.LinearGradient(w/2, 0, w/2, h*3)
lg.add_color_stop_rgba(0, 0, 0, 0, 1)
lg.add_color_stop_rgba(h, 0.2, 0.2, 0.2, 1)

cr.set_source(lg)
cr.paint()

背景充满了渐变的油漆。 涂料是从黑色到深灰色的平滑混合。

cr.translate(0, 2 * self.imageHeight + self.gap)
cr.scale(1, -1)

此代码翻转图像并将其转换为原始图像下方。 平移操作是必需的,因为缩放操作会使图像上下颠倒并向上平移图像。 要了解发生了什么,只需拍摄一张照片并将其放在桌子上即可。 现在翻转它。

cr.rectangle(self.border, self.imageHeight-i, self.imageWidth, 1)

i = i + 1

cr.save()
cr.clip()
cr.set_source_surface(self.surface, self.border, self.border)
alpha = alpha - step
cr.paint_with_alpha(alpha)
cr.restore()

这是最后一部分。 我们使第二个图像透明。 但是透明度不是恒定的。 图像逐渐淡出。 反射的图像逐行绘制。 clip()方法将图形限制为高度为 1 的矩形。paint_with_alpha()在绘制图像表面的当前片段时会考虑透明度。

Reflection

图:反射

等待

在此示例中,我们使用透明效果创建一个等待演示。 我们将绘制 8 条线,这些线将逐渐消失,从而产生一条线在移动的错觉。 这种效果通常用于通知用户,一项艰巨的任务正在幕后进行。 一个示例是通过互联网流式传输视频。

waiting.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This program creates an
# waiting effect
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import gtk
import glib
import math
import cairo

trs = (
    ( 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 ),
    ( 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 ),
    ( 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 ),
    ( 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65 ),
    ( 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 ),
    ( 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 ),
    ( 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 ),
    ( 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0, )
)

class PyApp(gtk.Window):

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Waiting")
        self.set_size_request(250, 150)
        self.set_position(gtk.WIN_POS_CENTER)

        self.connect("destroy", gtk.main_quit)

        self.darea = gtk.DrawingArea()
        self.darea.connect("expose-event", self.expose)
        self.add(self.darea)

        self.count = 0

        glib.timeout_add(100, self.on_timer)

        self.show_all()

    def on_timer(self):
        self.count = self.count + 1
        self.darea.queue_draw()
        return True

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        cr.set_line_width(3)
        cr.set_line_cap(cairo.LINE_CAP_ROUND)

        w = self.allocation.width
        h = self.allocation.height

        cr.translate(w/2, h/2)

        for i in range(8):
            cr.set_source_rgba(0, 0, 0, trs[self.count%8][i])
            cr.move_to(0.0, -10.0)
            cr.line_to(0.0, -40.0)
            cr.rotate(math.pi/4)
            cr.stroke()

PyApp()
gtk.main()

我们用八个不同的 alpha 值绘制八条线。

glib.timeout_add(100, self.on_timer)

我们使用计时器函数来创建动画。

trs = (
    ( 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 ),
    ...
)

这是此演示中使用的透明度值的二维元组。 有 8 行,每行一种状态。 8 行中的每行将连续使用这些值。

cr.set_line_width(3)
cr.set_line_cap(cairo.LINE_CAP_ROUND)

我们使线条更粗一些,以便更好地显示它们。 我们用圆帽画线。 他们看起来更好。

cr.set_source_rgba(0, 0, 0, trs[self.count%8][i]

在这里,我们定义了一条线的透明度值。

cr.move_to(0.0, -10.0)
cr.line_to(0.0, -40.0)
cr.rotate(math.pi/4)
cr.stroke()

这些代码行将绘制八行中的每行。

Waiting

图:等待

在 PyGTK 编程库的这一章中,我们使用 Cairo 库进行了一些更高级的绘制。

PyGTK 中的贪食蛇游戏

原文: http://zetcode.com/gui/pygtk/snake/

在 PyGTK 编程教程的这一部分中,我们将创建一个贪食蛇游戏克隆。

贪食蛇游戏

贪食蛇是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。 该游戏有时称为 Nibbles 。

开发

蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 如果游戏结束,我们将在棋盘中间显示"Game Over"消息。

snake.py

#!/usr/bin/python

# ZetCode PyGTK tutorial 
#
# This is a simple snake game
# clone
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009

import sys
import gtk
import cairo
import random
import glib

WIDTH = 300
HEIGHT = 270
DOT_SIZE = 10
ALL_DOTS = WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE)
RAND_POS = 26

x = [0] * ALL_DOTS
y = [0] * ALL_DOTS

class Board(gtk.DrawingArea):

    def __init__(self):
        super(Board, self).__init__()

        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0, 0))
        self.set_size_request(WIDTH, HEIGHT)

        self.connect("expose-event", self.expose)

        self.init_game()

    def on_timer(self):

        if self.inGame:
            self.check_apple()
            self.check_collision()
            self.move()
            self.queue_draw()
            return True
        else:
            return False

    def init_game(self):

        self.left = False
        self.right = True
        self.up = False
        self.down = False
        self.inGame = True
        self.dots = 3

        for i in range(self.dots):
            x[i] = 50 - i * 10
            y[i] = 50

        try:
            self.dot = cairo.ImageSurface.create_from_png("dot.png")
            self.head = cairo.ImageSurface.create_from_png("head.png")
            self.apple = cairo.ImageSurface.create_from_png("apple.png")
        except Exception, e:
            print e.message
            sys.exit(1)

        self.locate_apple()
        glib.timeout_add(100, self.on_timer)

    def expose(self, widget, event):

        cr = widget.window.cairo_create()

        if self.inGame:
            cr.set_source_rgb(0, 0, 0)
            cr.paint()

            cr.set_source_surface(self.apple, self.apple_x, self.apple_y)
            cr.paint()

            for z in range(self.dots):
                if (z == 0): 
                    cr.set_source_surface(self.head, x[z], y[z])
                    cr.paint()
                else:
                    cr.set_source_surface(self.dot, x[z], y[z])                 
                    cr.paint()
        else:
            self.game_over(cr)

    def game_over(self, cr):

        w = self.allocation.width / 2
        h = self.allocation.height / 2

        (x, y, width, height, dx, dy) = cr.text_extents("Game Over")

        cr.set_source_rgb(65535, 65535, 65535)
        cr.move_to(w - width/2, h)
        cr.show_text("Game Over")
        self.inGame = False

    def check_apple(self):

        if x[0] == self.apple_x and y[0] == self.apple_y: 
            self.dots = self.dots + 1
            self.locate_apple()

    def move(self):

        z = self.dots

        while z > 0:
            x[z] = x[(z - 1)]
            y[z] = y[(z - 1)]
            z = z - 1

        if self.left:
            x[0] -= DOT_SIZE

        if self.right: 
            x[0] += DOT_SIZE

        if self.up:
            y[0] -= DOT_SIZE

        if self.down:
            y[0] += DOT_SIZE

    def check_collision(self):

        z = self.dots

        while z > 0:
            if z > 4 and x[0] == x[z] and y[0] == y[z]:
                self.inGame = False
            z = z - 1

        if y[0] > HEIGHT - DOT_SIZE: 
            self.inGame = False

        if y[0] < 0:
            self.inGame = False

        if x[0] > WIDTH - DOT_SIZE:
            self.inGame = False

        if x[0] < 0:
            self.inGame = False

    def locate_apple(self):

        r = random.randint(0, RAND_POS)
        self.apple_x = r * DOT_SIZE
        r = random.randint(0, RAND_POS)
        self.apple_y = r * DOT_SIZE

    def on_key_down(self, event): 

        key = event.keyval

        if key == gtk.keysyms.Left and not self.right: 
            self.left = True
            self.up = False
            self.down = False

        if key == gtk.keysyms.Right and not self.left:
            self.right = True
            self.up = False
            self.down = False

        if key == gtk.keysyms.Up and not self.down:
            self.up = True
            self.right = False
            self.left = False

        if key == gtk.keysyms.Down and not self.up: 
            self.down = True
            self.right = False
            self.left = False

class Snake(gtk.Window):

    def __init__(self):
        super(Snake, self).__init__()

        self.set_title('Snake')
        self.set_size_request(WIDTH, HEIGHT)
        self.set_resizable(False)
        self.set_position(gtk.WIN_POS_CENTER)

        self.board = Board()
        self.connect("key-press-event", self.on_key_down)
        self.add(self.board)

        self.connect("destroy", gtk.main_quit)
        self.show_all()

    def on_key_down(self, widget, event): 

        key = event.keyval
        self.board.on_key_down(event)

Snake()
gtk.main()

首先,我们将定义一些在游戏中使用的全局变量。

WIDTHHEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。

x = [0] * ALL_DOTS
y = [0] * ALL_DOTS

这两个列表存储蛇的所有可能关节的 x,y 坐标。

init_game()方法初始化变量,加载图像并启动超时功能。

self.left = False
self.right = True
self.up = False
self.down = False
self.inGame = True
self.dots = 3

游戏开始时,蛇有三个关节。 而且它正在向右行驶。

move()方法中,我们有游戏的关键算法。 要了解它,请查看蛇的运动方式。 您控制蛇的头。 您可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。

while z > 0:
    x[z] = x[(z - 1)]
    y[z] = y[(z - 1)]
    z = z - 1

该代码将关节向上移动。

if self.left:
    x[0] -= DOT_SIZE

将头向左移动。

checkCollision()方法中,我们确定蛇是否击中了自己或撞墙之一。

while z > 0:
    if z > 4 and x[0] == x[z] and y[0] == y[z]:
        self.inGame = False
    z = z - 1

如果蛇用头撞到关节之一,我们就结束游戏。

if y[0] > HEIGHT - DOT_SIZE: 
    self.inGame = False

如果蛇击中了棋盘的底部,我们就结束了游戏。

locate_apple()方法在表格上随机定位一个苹果。

r = random.randint(0, RAND_POS)

我们得到一个从 0 到RAND_POS-1的随机数。

self.apple_x = r * DOT_SIZE
...
self.apple_y = r * DOT_SIZE

这些行设置了apple对象的 x,y 坐标。

    self.connect("key-press-event", self.on_key_down)
    ...

def on_key_down(self, widget, event): 

    key = event.keyval
    self.board.on_key_down(event)

我们在Snake类中捕获按键事件,并将处理委托给board对象。

Board类的on_key_dow()方法中,我们确定玩家按下了哪些键。

if key == gtk.keysyms.Left and not self.right: 
    self.left = True
    self.up = False
    self.down = False

如果我们按左光标键,则将self.left变量设置为True。 在move()方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。

Snake

图:贪食蛇

这是使用 PyGTK 编程库编程的贪食蛇电脑游戏。

PyGTK 中的自定义小部件

原文: http://zetcode.com/gui/pygtk/customwidget/

工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。

客户程序员必须创建更专业的小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能:程序员可以修改或增强现有的小部件,或者可以从头开始创建自定义小部件。

刻录小部件

这是我们从头开始创建的小部件的示例。 可以在各种媒体刻录应用(例如 Nero 刻录 ROM)中找到此小部件。

burning.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

# ZetCode PyGTK tutorial 
#
# This example creates a burning
# custom widget
#
# author: Jan Bodnar
# website: zetcode.com 
# last edited: April 2011

import gtk
import cairo

class Burning(gtk.DrawingArea):

    def __init__(self, parent):

        self.par = parent
        super(Burning, self).__init__()

        self.num = ( "75", "150", "225", "300", 
            "375", "450", "525", "600", "675" )

        self.set_size_request(-1, 30)
        self.connect("expose-event", self.expose)

    def expose(self, widget, event):

        cr = widget.window.cairo_create()
        cr.set_line_width(0.8)

        cr.select_font_face("Courier", 
            cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
        cr.set_font_size(11)

        width = self.allocation.width

        self.cur_width = self.par.get_cur_value()

        step = round(width / 10.0)

        till = (width / 750.0) * self.cur_width
        full = (width / 750.0) * 700

        if (self.cur_width >= 700):

            cr.set_source_rgb(1.0, 1.0, 0.72)
            cr.rectangle(0, 0, full, 30)
            cr.save()
            cr.clip()
            cr.paint()
            cr.restore()

            cr.set_source_rgb(1.0, 0.68, 0.68)
            cr.rectangle(full, 0, till-full, 30)
            cr.save()
            cr.clip()
            cr.paint()
            cr.restore()

        else:     
            cr.set_source_rgb(1.0, 1.0, 0.72)
            cr.rectangle(0, 0, till, 30)
            cr.save()
            cr.clip()
            cr.paint()
            cr.restore()

        cr.set_source_rgb(0.35, 0.31, 0.24)

        for i in range(1, len(self.num) + 1):
            cr.move_to(i*step, 0)
            cr.line_to(i*step, 5)
            cr.stroke()

            (x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1])
            cr.move_to(i*step-width/2, 15)
            cr.text_path(self.num[i-1])
            cr.stroke()

class PyApp(gtk.Window): 

    def __init__(self):
        super(PyApp, self).__init__()

        self.set_title("Burning")
        self.set_size_request(350, 200)        
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", gtk.main_quit)

        self.cur_value = 0

        vbox = gtk.VBox(False, 2)

        scale = gtk.HScale()
        scale.set_range(0, 750)
        scale.set_digits(0)
        scale.set_size_request(160, 40)
        scale.set_value(self.cur_value)
        scale.connect("value-changed", self.on_changed)

        fix = gtk.Fixed()
        fix.put(scale, 50, 50)

        vbox.pack_start(fix)

        self.burning = Burning(self)
        vbox.pack_start(self.burning, False, False, 0)

        self.add(vbox)
        self.show_all()

    def on_changed(self, widget):
        self.cur_value = widget.get_value()
        self.burning.queue_draw()

    def get_cur_value(self):
        return self.cur_value

PyApp()
gtk.main()

我们在窗口底部放置一个DrawingArea并手动绘制整个窗口小部件。 所有重要的代码都驻留在Burning类的expose()方法中。 此小部件以图形方式显示了介质的总容量和可供我们使用的可用空间。 该小部件由比例小部件控制。 自定义窗口小部件的最小值为 0,最大值为 750。如果值达到 700,则开始绘制红色。 这通常表示过度燃烧。

self.num = ( "75", "150", "225", "300", 
    "375", "450", "525", "600", "675" )

这些数字显示在刻录小部件上。 它们显示了介质的容量。

self.cur_width = self.par.get_cur_value()

这两行从刻度小部件获取当前数字。 我们获得父窗口小部件,并从父窗口小部件中获得当前值。

till = (width / 750.0) * self.cur_width
full = (width / 750.0) * 700

直到参数确定要绘制的总大小。 该值来自滑块小部件。 它占整个面积的一部分。 full参数确定了我们开始绘制红色的点。

cr.set_source_rgb(1.0, 1.0, 0.72)
cr.rectangle(0, 0, till, 30)
cr.save()
cr.clip()
cr.paint()
cr.restore()

此代码在此处绘制了一个黄色矩形,直到介质充满为止。

(x, y, width, height, dx, dy) = cr.text_extents(self.num[i-1])
cr.move_to(i*step-width/2, 15)
cr.text_path(self.num[i-1])
cr.stroke()

这里的代码在刻录小部件上绘制数字。 我们计算TextExtents来正确定位文本。

def on_changed(self, widget):
    self.cur_value = widget.get_value()
    self.burning.queue_draw()

我们从小部件中获取值,并将其存储在cur_value变量中以备后用。 我们重新绘制刻录的小部件。

Burning widget

图:刻录小部件

在本章中,我们在 PyGTK 中创建了一个自定义小部件。

PHP GTK 教程

原文: http://zetcode.com/gui/phpgtktutorial/

这是 PHP GTK 教程。 在本教程中,您将学习使用 PHP 语言在 GTK 中进行 GUI 编程的基础。 本教程适合初学者。

目录

GTK

GTK 是用于创建图形用户界面的库。 该库是用 C 编程语言创建的。 GTK 库也称为 GIMP 工具包。 最初,该库是在开发 GIMP 图像处理器时创建的。 从那时起,GTK 成为 Linux 和 BSD Unix 下最受欢迎的工具包之一。 如今,开源世界中的大多数 GUI 软件都是在 Qt 或 GTK 中创建的。 存在用于 C++ ,Python,PHP,Perl,Java,C# 和其他编程语言的语言绑定。

相关教程

ZetCode 上有 PHP 教程。 您可能也对 Ruby GTK 教程PyGTK 教程JavaScript GTK 教程感兴趣。

PyQt5 小部件 II

原文: http://zetcode.com/gui/pyqt5/widgets2/

在这里,我们将继续介绍 PyQt5 小部件。 我们将介绍QPixmapQLineEditQSplitterQComboBox

QPixmap

QPixmap是用于处理图像的小部件之一。 它经过优化,可在屏幕上显示图像。 在我们的代码示例中,我们将使用QPixmap在窗口上显示图像。

pixmap.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

In this example, we dispay an image
on the window. 

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import (QWidget, QHBoxLayout, 
    QLabel, QApplication)
from PyQt5.QtGui import QPixmap
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        hbox = QHBoxLayout(self)
        pixmap = QPixmap("redrock.png")

        lbl = QLabel(self)
        lbl.setPixmap(pixmap)

        hbox.addWidget(lbl)
        self.setLayout(hbox)

        self.move(300, 200)
        self.setWindowTitle('Red Rock')
        self.show()        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们在窗口上显示图像。

pixmap = QPixmap("redrock.png")

我们创建一个QPixmap对象。 它以文件名作为参数。

lbl = QLabel(self)
lbl.setPixmap(pixmap)

我们将像素图放入QLabel小部件。

QLineEdit

QLineEdit是一个小部件,允许输入和编辑单行纯文本。 该小部件具有撤消和重做,剪切和粘贴以及拖放功能。

lineedit.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This example shows text which 
is entered in a QLineEdit
in a QLabel widget.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

import sys
from PyQt5.QtWidgets import (QWidget, QLabel, 
    QLineEdit, QApplication)

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.lbl = QLabel(self)
        qle = QLineEdit(self)

        qle.move(60, 100)
        self.lbl.move(60, 40)

        qle.textChanged[str].connect(self.onChanged)

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('QLineEdit')
        self.show()

    def onChanged(self, text):

        self.lbl.setText(text)
        self.lbl.adjustSize()        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

此示例显示了行编辑小部件和标签。 我们在行编辑中键入的文本会立即显示在标签窗口小部件中。

qle = QLineEdit(self)

QLineEdit小部件已创建。

qle.textChanged[str].connect(self.onChanged)

如果行编辑窗口小部件中的文本更改,我们将调用onChanged()方法。

def onChanged(self, text):

    self.lbl.setText(text)
    self.lbl.adjustSize() 

onChanged()方法内部,我们将键入的文本设置为标签小部件。 我们调用adjustSize()方法将标签的大小调整为文本的长度。

QLineEdit

图:QLineEdit

QSplitter

QSplitter允许用户通过拖动子控件之间的边界来控制子控件的大小。 在我们的示例中,我们显示了由两个拆分器组成的三个QFrame小部件。

splitter.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This example shows
how to use QSplitter widget.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QFrame, 
    QSplitter, QStyleFactory, QApplication)
from PyQt5.QtCore import Qt
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        hbox = QHBoxLayout(self)

        topleft = QFrame(self)
        topleft.setFrameShape(QFrame.StyledPanel)

        topright = QFrame(self)
        topright.setFrameShape(QFrame.StyledPanel)

        bottom = QFrame(self)
        bottom.setFrameShape(QFrame.StyledPanel)

        splitter1 = QSplitter(Qt.Horizontal)
        splitter1.addWidget(topleft)
        splitter1.addWidget(topright)

        splitter2 = QSplitter(Qt.Vertical)
        splitter2.addWidget(splitter1)
        splitter2.addWidget(bottom)

        hbox.addWidget(splitter2)
        self.setLayout(hbox)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('QSplitter')
        self.show()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们有三个框架小部件和两个拆分器。 请注意,在某些主题下,拆分器可能无法很好地显示。

topleft = QFrame(self)
topleft.setFrameShape(QFrame.StyledPanel)

我们使用样式化的框架以查看QFrame小部件之间的边界。

splitter1 = QSplitter(Qt.Horizontal)
splitter1.addWidget(topleft)
splitter1.addWidget(topright)

我们创建一个QSplitter小部件,并在其中添加两个框架。

splitter2 = QSplitter(Qt.Vertical)
splitter2.addWidget(splitter1)

我们还可以将拆分器添加到另一个拆分器小部件。

QSplitter widget

图:QSplitter小部件

QComboBox

QComboBox是一个小部件,允许用户从选项列表中进行选择。

combobox.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This example shows how to use 
a QComboBox widget.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import (QWidget, QLabel, 
    QComboBox, QApplication)
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.lbl = QLabel("Ubuntu", self)

        combo = QComboBox(self)
        combo.addItem("Ubuntu")
        combo.addItem("Mandriva")
        combo.addItem("Fedora")
        combo.addItem("Arch")
        combo.addItem("Gentoo")

        combo.move(50, 50)
        self.lbl.move(50, 150)

        combo.activated[str].connect(self.onActivated)        

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('QComboBox')
        self.show()

    def onActivated(self, text):

        self.lbl.setText(text)
        self.lbl.adjustSize()  

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

该示例显示了QComboBoxQLabel。 组合框具有五个选项的列表。 这些是 Linux 发行版的名称。 标签窗口小部件显示从组合框中选择的选项。

combo = QComboBox(self)
combo.addItem("Ubuntu")
combo.addItem("Mandriva")
combo.addItem("Fedora")
combo.addItem("Arch")
combo.addItem("Gentoo")

我们创建具有五个选项的QComboBox小部件。

combo.activated[str].connect(self.onActivated) 

选择项目后,我们调用onActivated()方法。

def onActivated(self, text):

    self.lbl.setText(text)
    self.lbl.adjustSize() 

在方法内部,我们将所选项目的文本设置为标签小部件。 我们调整标签的大小。

QComboBox

图:QComboBox

在 PyQt5 教程的这一部分中,我们介绍了QPixmapQLineEditQSplitterQComboBox

PHP GTK 简介

原文: http://zetcode.com/gui/phpgtktutorial/introduction/

在 PHP GTK 编程教程的这一部分中,我们将介绍 GTK 库并使用 PHP 编程语言创建第一个程序。

本教程的目的是使您开始使用 GTK 和 PHP。 GTK 是用于创建图形用户界面的领先工具包之一。 PHP 是服务器端 Web 开发中使用的非常流行的脚本语言。 它也可以用于通过 PHP CLI,PHP 命令行界面创建命令行脚本。

PHP-GTK

PHP-GTK 是 PHP 编写 GTK 应用的语言绑定。 PHP-GTK 为 GTK 类和函数提供了一个面向对象的接口。 该项目的主页位于 gtk.php.net 上。 在那里我们找到了参考文档。

为了运行示例,我们需要安装 PHP-CLI,PHP-GTK 和用于 PHP 的 Cairo。

安装

在撰写本教程时,在 Linux 上安装 PHP-GTK 存在问题。 (将在专门介绍用 Cairo 进行绘图的章节中说明为 PHP 安装 Cairo。)

以下是必需的包:

build-essential subversion php5-cli php5-dev libgtk2.0-dev libglade2-dev

如果您没有这些之一,则必须安装它们。

svn co http://svn.php.net/repository/gtk/php-gtk/trunk php-gtk

现在,从 Subversion 树中下载源代码。 不要使用源压缩文件。 这些说明适用于 Subversion 仓库中的源。

./buildconf
./configure
make
sudo make install

这些是用于构建 PHP-GTK 的命令。 但是,在此过程中我们可能会遇到问题。 这是由于过去 libtool 的更改。

./configure: line 11641: LTOPTIONS_VERSION: command not found
./configure: line 11642: LTSUGAR_VERSION: command not found
./configure: line 11643: LTVERSION_VERSION: command not found
./configure: line 11644: LTOBSOLETE_VERSION: command not foun

配置脚本给出错误消息。

$ pwd
/home/vronskij/Downloads/php-gtk
$ cat /usr/share/aclocal/ltoptions.m4 /usr/share/aclocal/ltversion.m4 \
    /usr/share/aclocal/ltsugar.m4 /usr/share/aclocal/lt~obsolete.m4 >> aclocal.m4

现在在构建目录中,发出上面的命令。 我们的目录中将有一个新文件aclocal.m4。 (可在 ubuntuforums.org 上找到提示。)希望现在可以运行配置脚本。

extension=php_gtk2.so

最后一步是编辑php.ini文件,并将以上行添加到“动态扩展”部分下。

简单的例子

既然我们已经成功安装了 PHP-GTK 库,我们可以从一个小例子开始。 在此示例中,我们创建一个简单的窗口。 窗口在屏幕上居中。

<?php

/* 
ZetCode PHP GTK tutorial

This program centers a window on 
the screen.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->set_title('Simple'); 
        $this->set_default_size(250, 150); 

        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show(); 
    } 
} 

new Example(); 
Gtk::main(); 
?>

本示例在屏幕中央显示一个250x150像素的窗口。

class Example extends GtkWindow { 

Example类基于GtkWindow小部件。

$this->set_title('Simple'); 

set_title()方法设置窗口的标题。

$this->set_default_size(250, 150); 

此行设置窗口的大小。 它将是 250px 宽和 150px 高。

$this->connect_simple('destroy', array('gtk', 'main_quit')); 

在这里,我们将destroy信号连接到回调。 main_quit()方法永久退出该应用。 单击标题栏中的关闭按钮,或按 Alt + F4 时,会发出破坏信号。

$this->set_position(GTK::WIN_POS_CENTER);

这条线使窗口在屏幕上居中。

$this->show();

一切准备就绪后,我们在屏幕上显示窗口。

new Example(); 
Gtk::main(); 

我们设置了应用。 创建无限循环。 从这一点开始,应用就坐下来,等待用户或系统的外部事件。 循环一直运行到终止为止。

Simple

图:简单

创建工具提示

第二个示例将显示一个工具提示。 工具提示是一个小的矩形窗口,它提供有关对象的简短信息。 它通常是一个 GUI 组件。 它是应用帮助系统的一部分。

<?php

/* 
ZetCode PHP GTK tutorial

This code shows a tooltip on 
a window and a button.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Tooltips');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();
        $this->add($fixed);

        $button = new GtkButton("Button");
        $button->set_size_request(80, 35);
        $button->set_tooltip_text("Button widget");

        $fixed->put($button, 50, 50);

        $this->set_tooltip_text("Window widget");

        $this->set_default_size(250, 150); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

该示例创建一个窗口。 如果将鼠标指针悬停在窗口区域上方,则会弹出一个工具提示。

$this->init_ui();

接口的创建委托给init_ui()方法。

$fixed = new GtkFixed();
$this->add($fixed);

GtkFixed是一个容器窗口小部件,用于将窗口小部件定位在绝对坐标上。 第二行将此容器设置为示例的GtkWindow。 一扇窗口有一个中央容器。

$button->set_tooltip_text("Button widget");

我们使用set_tooltip_text()方法设置按钮的工具提示。

$this->set_tooltip_text("Window widget");

我们为窗口设置工具提示。 通过$this变量访问该窗口。

$this->show_all(); 

当窗口上有多个小部件时,我们有两个选择。 在所有小部件上调用show(),或调用show_all()(显示容器及其所有子代)。

Tooltips

图:工具提示 s

退出按钮

在本节的最后一个示例中,我们将创建一个退出按钮。 当我们按下此按钮时,应用终止。

<?php

/* 
ZetCode PHP GTK tutorial

This program creates a quit
button. When we press the button,
the application terminates. 

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Quit button');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();
        $this->add($fixed);

        $button = new GtkButton("Quit");
        $button->set_size_request(80, 35);
        $button->connect_simple('clicked', array('gtk', 'main_quit'));

        $fixed->put($button, 50, 50);

        $this->set_default_size(250, 150); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

示例的源代码。

$button = new GtkButton("Quit");

在这里,我们创建一个按钮小部件。 构造器的参数是按钮的标签。

$button->set_size_request(80, 35);

我们设置按钮的大小。

$button->connect_simple('clicked', array('gtk', 'main_quit'));

我们将main_quit()方法插入按钮点击信号。

$fixed->put($button, 50, 50);

我们将退出按钮放入x = 50y = 50的固定容器中。

本节介绍了使用 PHP 语言的 GTK 库。

PHP GTK 中的布局管理

原文: http://zetcode.com/gui/phpgtktutorial/layoutmanagement/

在本章中,我们将展示如何在窗口或对话框中布置窗口小部件。

在设计应用的 GUI 时,我们决定要使用哪些小部件以及如何在应用中组织这些小部件。 为了组织窗口小部件,我们使用专门的不可见窗口小部件,称为布局容器。 在本章中,我们将提到GtkAlignmentGtkFixedGtkVBoxGtkTable

GtkFixed

GtkFixed容器将子窗口小部件放置在固定位置并具有固定大小。 此容器不执行自动布局管理。 在大多数应用中,我们不使用此容器。 我们在某些专业领域使用它。 例如游戏,使用图表的专用应用,可以移动的可调整大小的组件(如电子表格应用中的图表),小型教育示例。

<?php

/* 
ZetCode PHP GTK tutorial

In this program, we lay out widgets
using absolute positioning.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Fixed');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->modify_bg(Gtk::STATE_NORMAL, new GdkColor(6400, 6400, 6440));

        $bardejov = GtkImage::new_from_file("bardejov.jpg");
        $rotunda = GtkImage::new_from_file("rotunda.jpg");
        $mincol = GtkImage::new_from_file("mincol.jpg");

        $fixed = new GtkFixed();
        $fixed->put($bardejov, 20, 20);
        $fixed->put($rotunda, 40, 160);
        $fixed->put($mincol, 170, 50);

        $this->add($fixed);        

        $this->set_default_size(300, 280); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         

    }
} 

new Example(); 
Gtk::main();

?>

在我们的示例中,我们在窗口上显示了三个小图像。 我们明确指定放置这些图像的 x,y 坐标。

$this->modify_bg(Gtk::STATE_NORMAL, new GdkColor(6400, 6400, 6440));

为了获得更好的视觉体验,我们将背景色更改为深灰色。

$bardejov = GtkImage::new_from_file("bardejov.jpg");

GtkImage是用于显示图像的小部件。 图片是从磁盘上的文件加载的。

$fixed = new GtkFixed();

我们创建GtkFixed容器。

$fixed->put($bardejov, 20, 20);

我们将第一个图像放置在x = 20y = 20坐标处。

w.add(fixed);

最后,我们将GtkFixed容器添加到窗口中。

Fixed

图:固定

按钮

在此代码示例中,我们将使用垂直框,水平框和对齐小部件。 水平框将小部件排列为一行。 同样,垂直框将其小部件放在一列中。 Alignment容器控制其子窗口小部件的对齐方式和大小。

<?php

/* 
ZetCode PHP GTK tutorial

In this program, we position two buttons
in the bottom right corner of the window.
We use horizontal and vertical boxes.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Buttons');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 
        $this->set_border_width(3);

        $vbox = new GtkVBox(false, 5);
        $hbox = new GtkHBox(true, 3);

        $frame = new GtkFrame();
        $vbox->pack_start($frame, true, true, 0);

        $okButton = new GtkButton("OK");
        $okButton->set_size_request(70, 30);
        $closeButton = new GtkButton("Close");

        $hbox->add($okButton);
        $hbox->add($closeButton);

        $halign = new GtkAlignment(1, 0, 0, 0);
        $halign->add($hbox);
        $vbox->pack_start($halign, false, false, 3);

        $this->add($vbox);        

        $this->set_default_size(260, 150); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();          
    }
} 

new Example(); 
Gtk::main();

?>

在代码示例中,我们在窗口的右下角放置了两个按钮。 为此,我们使用一个水平框,一个垂直框和一个对齐容器。

$vbox = new GtkVBox(false, 5);

将创建一个垂直框容器。 我们将同构成员设置为false。 这意味着放在垂直框中的窗口小部件将具有相同的大小。 小部件之间的垂直间距设置为 5 像素。

$frame = new GtkFrame();

在这里,我们创建一个GtkFrame小部件。 该小部件的目的是占用两个按钮上方的空间。

$vbox->pack_start($frame, true, true, 0);

在这里,我们将框架小部件放入垂直框中。 该方法的第一个参数是小部件,它被放置在框中。 以下三个参数是expandfillpaddingexpand参数设置为true,这意味着将在小部件周围分配可用空间。 当fill参数设置为true时,小部件实际上会占用其周围的所有可用空间。 子窗口小部件周围没有填充。

$hbox = new GtkHBox(true, 3);  

此代码行创建一个水平框。 框内的所有小部件都将具有相同的大小。 小部件之间的水平间隔为 3px。

$okButton = new GtkButton("OK");
$okButton->set_size_request(70, 30);
$closeButton = new GtkButton("Close");

$hbox->add($okButton);
$hbox->add($closeButton);

我们创建两个按钮,并将它们放在水平框中。

$halign = new GtkAlignment(1, 0, 0, 0);
$halign->add($hbox);
$vbox->pack_start($halign, false, false, 3);

这将创建一个对齐容器,它将其子窗口小部件放在右侧。 设置为 1.0 的xalign成员会将所有可用空间放在水平框的左侧。 这将向右推两个按钮。 我们将水平框添加到对齐容器中,然后将对齐容器包装到垂直框中。 我们必须记住,对齐容器仅包含一个子窗口小部件。 这就是为什么我们必须使用水平框。

Buttons

图:按钮

计算器骨架

GtkTable小部件按行和列排列小部件。

<?php

/* 
ZetCode PHP GTK tutorial

In this program we create a skeleton of
a calculator. We use the GtkTable widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Calculator');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $vbox = new GtkVBox(false, 2);

        $mb = new GtkMenubar();
        $filemenu = new GtkMenu();
        $filemi = new GtkMenuItem("File");
        $filemi->set_submenu($filemenu);
        $mb->append($filemi);

        $vbox->pack_start($mb, false, false, 0);

        $table = new GtkTable(5, 4, true);

        $table->attach_defaults(new GtkButton("Cls"), 0, 1, 0, 1);
        $table->attach_defaults(new GtkButton("Bck"), 1, 2, 0, 1);
        $table->attach_defaults(new GtkLabel(), 2, 3, 0, 1);
        $table->attach_defaults(new GtkButton("Close"), 3, 4, 0, 1);

        $table->attach_defaults(new GtkButton("7"), 0, 1, 1, 2);
        $table->attach_defaults(new GtkButton("8"), 1, 2, 1, 2);
        $table->attach_defaults(new GtkButton("9"), 2, 3, 1, 2);
        $table->attach_defaults(new GtkButton("/"), 3, 4, 1, 2);

        $table->attach_defaults(new GtkButton("4"), 0, 1, 2, 3);
        $table->attach_defaults(new GtkButton("5"), 1, 2, 2, 3);
        $table->attach_defaults(new GtkButton("6"), 2, 3, 2, 3);
        $table->attach_defaults(new GtkButton("*"), 3, 4, 2, 3);

        $table->attach_defaults(new GtkButton("1"), 0, 1, 3, 4);
        $table->attach_defaults(new GtkButton("2"), 1, 2, 3, 4);
        $table->attach_defaults(new GtkButton("3"), 2, 3, 3, 4);
        $table->attach_defaults(new GtkButton("-"), 3, 4, 3, 4);

        $table->attach_defaults(new GtkButton("0"), 0, 1, 4, 5);
        $table->attach_defaults(new GtkButton("."), 1, 2, 4, 5);
        $table->attach_defaults(new GtkButton("="), 2, 3, 4, 5);
        $table->attach_defaults(new GtkButton("+"), 3, 4, 4, 5);

        $vbox->pack_start(new GtkEntry(), false, false, 0);
        $vbox->pack_end($table, true, true, 0);

        $this->add($vbox);        

        $this->set_default_size(300, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         

    }
} 

new Example(); 
Gtk::main();

?>

我们使用GtkTable小部件创建一个计算器框架。

$table = new GtkTable(5, 4, true);

我们创建一个具有 5 行 4 列的表小部件。 第三个参数是同质参数。 如果设置为true,则表中的所有小部件都具有相同的大小。 所有窗口小部件的大小等于表容器中最大的窗口小部件。

$table->attach_defaults(new GtkButton("Cls"), 0, 1, 0, 1);

我们在表格容器上附加一个按钮。 到表格的左上方单元格。 前两个参数是单元格的左侧和右侧,后两个参数是单元格的顶部和左侧。

$vbox->pack_end($table, true, true, 0);

我们将表格小部件打包到垂直框中。

Calculator skeleton

图:计算机骨架

窗口

接下来,我们将创建一个更高级的示例。 我们显示一个窗口,可以在 JDeveloper IDE 中找到它。

<?php

/* 
ZetCode PHP GTK tutorial

This is a more complicated layout example.
We use GtkAlignment and GtkTable widgets. 

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();
    } 

    public function init_ui() {

        $this->set_title('Windows');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->set_border_width(15);

        $table = new GtkTable(8, 4, false);
        $table->set_col_spacings(3);

        $title = new GtkLabel("Windows");

        $halign = new GtkAlignment(0, 0, 0, 0);
        $halign->add($title);        
        $table->attach($halign, 0, 1, 0, 1, GTK::FILL, 
            GTK::FILL, 0, 0);

        $frame = new GtkFrame();
        $table->attach($frame, 0, 2, 1, 3, GTK::FILL | Gtk::EXPAND,
            GTK::FILL | GTK::EXPAND, 1, 1);

        $activate = new GtkButton("Activate");
        $activate->set_size_request(50, 30);
        $table->attach($activate, 3, 4, 1, 2, GTK::FILL,
            GTK::SHRINK, 1, 1);

        $valign = new GtkAlignment(0, 0, 0, 0);
        $close = new GtkButton("Close");
        $close->set_size_request(70, 30);
        $valign->add($close);
        $table->set_row_spacing(1, 3);
        $table->attach($valign, 3, 4, 2, 3, Gtk::FILL,
            Gtk::FILL | Gtk::EXPAND, 1, 1);

        $halign2 = new GtkAlignment(0, 1, 0, 0);
        $help = new GtkButton("Help");
        $help->set_size_request(70, 30);
        $halign2->add($help);
        $table->set_row_spacing(3, 6);
        $table->attach($halign2, 0, 1, 4, 5, Gtk::FILL,
            Gtk::FILL, 0, 0);

        $ok = new GtkButton("OK");
        $ok->set_size_request(70, 30);
        $table->attach($ok, 3, 4, 4, 5, Gtk::FILL,
            Gtk::FILL, 0, 0);

        $this->add($table);        

        $this->set_default_size(300, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

该代码示例显示了如何在 PHP GTK 中创建类似的窗口。

$table = new GtkTable(8, 4, false);
$table->set_col_spacings(3);

该示例基于GtkTable容器。 列之间将有 3px 的间隔。

$title = new GtkLabel("Windows");

$halign = new GtkAlignment(0, 0, 0, 0);
$halign->add($title);        
$table->attach($halign, 0, 1, 0, 1, GTK::FILL, 
    GTK::FILL, 0, 0);

这段代码创建了一个向左对齐的标签。 标签放置在Table容器的第一列的第一行中。

$frame = new GtkFrame();
$table->attach($frame, 0, 2, 1, 3, GTK::FILL | Gtk::EXPAND,
    GTK::FILL | GTK::EXPAND, 1, 1);

框架小部件跨越两行两列。 它将消耗其周围的所有可用空间。 因此,占用了窗口的大部分区域。

$valign = new GtkAlignment(0, 0, 0, 0);
$close = new GtkButton("Close");
$close->set_size_request(70, 30);
$valign->add($close);
$table->set_row_spacing(1, 3);
$table->attach($valign, 3, 4, 2, 3, Gtk::FILL,
    Gtk::FILL | Gtk::EXPAND, 1, 1);

我们将关闭按钮放在框架小部件旁边,进入第四列。 (我们从零开始计数)将按钮添加到对齐小部件中,以便可以将其对齐到顶部。

$halign2 = new GtkAlignment(0, 1, 0, 0);
$help = new GtkButton("Help");
$help->set_size_request(70, 30);
$halign2->add($help);
$table->set_row_spacing(3, 6);
$table->attach($halign2, 0, 1, 4, 5, Gtk::FILL,
    Gtk::FILL, 0, 0);

将帮助按钮放置在对齐小部件中,以便可以在其表格单元格中使其对齐。 它位于第一列第五行。

$ok = new GtkButton("OK");
$ok->set_size_request(70, 30);
$table->attach($ok, 3, 4, 4, 5, Gtk::FILL,
    Gtk::FILL, 0, 0);

最后,单击确定按钮。 它位于第四列和第五行。

Windows

图:窗口

在 PHP GTK 教程的这一部分中,我们提到了小部件的布局管理。

PHP GTK 中的小部件

原文: http://zetcode.com/gui/phpgtktutorial/widgets/

在 PHP GTK 编程教程的这一部分中,我们将介绍一些小部件。

小部件是 GUI 应用的基本构建块。 多年来,几个小部件已成为所有 OS 平台上所有工具包中的标准。 例如,按钮,复选框或滚动条。 GTK 工具箱的理念是将小部件的数量保持在最低水平。 将创建更多专门的窗口小部件作为定制 GTK 窗口小部件。

GtkCheckButton

GtkCheckButton是具有两种状态的窗口小部件:开和关。 接通状态通过复选标记显示。 它用来表示一些布尔属性。

<?php

/* 
ZetCode PHP GTK tutorial

This program toggles the title of the
window with the GtkCheckButton widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('Check button');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();
        $this->add($fixed);

        $cb = new GtkCheckButton("Show title");
        $cb->set_active(true);
        $cb->connect('clicked', array($this, 'on_clicked'));
        $fixed->put($cb, 50, 50);     

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_clicked($sender) {

        if ($sender->get_active()) {
            $this->set_title("Check button");
        } else {
            $this->set_title("");
        }         
    }
} 

new Example(); 
Gtk::main();

?>

根据GtkCheckButton的状态,我们将在窗口的标题栏中显示标题。

$cb = new GtkCheckButton("Show title");

GtkCheckButton小部件已创建。 小部件的构造器采用一个参数,即标签。 标签显示在复选框旁边。

$cb->set_active(true);

默认情况下标题是可见的,因此我们默认情况下选中复选按钮。

$cb->connect('clicked', array($this, 'on_clicked'));

如果我们单击复选框小部件,则会发出单击的信号。 我们将on_clicked()方法挂接到信号上。

if ($sender->get_active()) {
    $this->set_title("Check button");
} else {
    $this->set_title("");
}     

如果选中该按钮,我们将显示标题。 get_active()方法用于确定检查按钮的状态。 set_title()方法用于设置窗口的标题。 为了清除窗口的标题,我们使用一个空字符串。

GtkCheckButton

图:GtkCheckButton

GtkLabel

GtkLabel小部件显示文本。 此小部件不支持用户交互。

<?php

/* 
ZetCode PHP GTK tutorial

In this example, we show a text on the
window. For this, we use the GtkLabel widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();
    } 

    private function init_ui() {

        // no trailing white space!
        $lyrics = <<<LYRICS
Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
You say why did you do it with him today?
and sniff me out like I was Tanqueray

cause you're my fella, my guy
hand me your stella and fly
by the time I'm out the door
you tear men down like Roger Moore

I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good
LYRICS;

        $this->set_title('GtkLabel');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->set_border_width(10);
        $label = new GtkLabel($lyrics);
        $this->add($label);

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

该代码示例在窗口上显示了一些歌词。

    // no trailing white space!
    $lyrics = <<<LYRICS
Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt

我们创建多行文本。 在 PHP 中,可以使用 Heredoc 语法创建多行文本。

$this->set_border_width(10);

GtkLabel周围有一些空白。

$label = new GtkLabel($lyrics);
$this->add($label);

GtkLabel小部件已创建并添加到窗口。

GtkLabel Widget

图:GtkLabel小部件

GtkEntry

GtkEntry是单行文本输入字段。 该小部件用于输入文本数据。

<?php

/* 
ZetCode PHP GTK tutorial

This example demonstrates the GtkEntry widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    private $label;

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('GtkEntry');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();              

        $this->label = new GtkLabel("...");
        $fixed->put($this->label, 60, 40);

        $entry = new GtkEntry();
        $fixed->put($entry, 60, 100);
        $entry->connect('key_release_event', array($this, 'on_key_release'));

        $this->add($fixed); 

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_key_release($sender, $event) {

        $this->label->set_text($sender->get_text());
    }
} 

new Example(); 
Gtk::main();

?>

此示例显示了条目小部件和标签。 我们输入的文本将立即显示在标签小部件中。

$entry = new GtkEntry();

GtkEntry小部件已创建。

$entry->connect('key_release_event', array($this, 'on_key_release'));

我们将on_key_release()方法插入GtkEntry小部件的key_release_event

public function on_key_release($sender, $event) {

    $this->label->set_text($sender->get_text());
}

在该方法内部,我们通过get_text()方法从GtkEntry小部件中获取文本,并使用标签的set_text()方法将其设置为标签。

GtkEntry Widget

图:GtkEntry小部件

GtkImage

GtkImage小部件显示图像。

<?php

/* 
ZetCode PHP GTK tutorial

This example demonstrates the GtkImage widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('Red Rock');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->set_border_width(2);
        $image = GtkImage::new_from_file("redrock.png");                        
        $this->add($image);

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

在我们的示例中,我们在窗口上显示图像。

$this->set_border_width(2);

我们在图像周围放置了一些空边框。

$image = GtkImage::new_from_file("redrock.png");

GtkImage小部件已创建。 我们使用静态new_from_file()方法从文件加载图像。 如果找不到或无法加载文件,则生成的GtkImage将显示损坏的图像图标。

$this->add($image);

窗口小部件已添加到容器中。

GtkComboBox

ComboBox是一个小部件,允许用户从选项列表中进行选择。


<?php

/* 
ZetCode PHP GTK tutorial

This example demonstrates the GtkComboBox widget

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    private $label;

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('GtkComboBox');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();
        $this->label = new GtkLabel('-');
        $fixed->put($this->label, 50, 140);

        $cb = GtkComboBox::new_text();
        $cb->connect('changed', array($this, 'on_changed'));

        $cb->append_text('Ubuntu');
        $cb->append_text('Mandriva');
        $cb->append_text('Redhat');
        $cb->append_text('Gentoo');
        $cb->append_text('Mint');

        $fixed->put($cb, 50, 30);

        $this->add($fixed);

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_changed($sender) {
        $this->label->set_label($sender->get_active_text());
    }
} 

new Example(); 
Gtk::main();

?>

该示例显示了一个组合框和一个标签。 组合框具有五个选项的列表。 这些是 Linux 发行版的名称。 标签窗口小部件显示了从组合框中选择的选项。

$cb = GtkComboBox::new_text();

GtkComboBox小部件已创建。 new_text()是创建仅显示字符串的GtkComboBox的方法。

$cb->append_text('Ubuntu');
$cb->append_text('Mandriva');
$cb->append_text('Redhat');
$cb->append_text('Gentoo');
$cb->append_text('Mint');

它充满了数据。

public function on_changed($sender) {
    $this->label->set_label($sender->get_active_text());
}

on_changed()方法内部,我们从组合框中获取选定的文本并将其设置为标签。

GtkComboBox

图:GtkComboBox

在 PHP GTK 教程的这一章中,我们展示了一些基本的小部件。

PHP GTK 中的菜单和工具栏

原文: http://zetcode.com/gui/phpgtktutorial/menustoolbars/

在 PHP GTK 编程教程的这一部分中,我们将使用菜单和工具栏。

GUI 应用中的常见部分是菜单栏。 菜单栏由称为菜单的对象组成。 顶层菜单在菜单栏上带有其标签。 菜单具有菜单项。 菜单项是在应用内部执行特定操作的命令。 菜单也可以具有子菜单,这些子菜单具有自己的菜单项。

简单菜单

在第一个示例中,我们将创建一个带有一个文件菜单的菜单栏。 该菜单将只有一个菜单项。 通过选择项目,应用退出。

<?php

/* 
ZetCode PHP GTK tutorial

This example shows a simple menu.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Simple menu');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->modify_bg(Gtk::STATE_NORMAL, new GdkColor(6400, 6400, 6440));

        $mb = new GtkMenuBar();

        $filemenu = new GtkMenu();
        $filemi = new GtkMenuItem("File");
        $filemi->set_submenu($filemenu);

        $exitmi = new GtkMenuItem("Exit");
        $exitmi->connect_simple('activate', array('gtk', 'main_quit'));              
        $filemenu->append($exitmi);

        $mb->append($filemi);

        $vbox = new GtkVBox(false, 2);
        $vbox->pack_start($mb, false, false, 0);

        $this->add($vbox);

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

这是一个最小的菜单栏功能示例。

$mb = new GtkMenuBar();

GtkMenuBar小部件已创建。 这是各个菜单的容器。

$filemenu = new GtkMenu();
$filemi = new GtkMenuItem("File");
$filemi->set_submenu($filemenu);

创建顶层GtkMenuItem。 菜单项代表 GUI 应用中的操作。

$exitmi = new GtkMenuItem("Exit");
$exitmi->connect_simple('activate', array('gtk', 'main_quit'));              
$filemenu->append($exitmi);

将创建出口GtkMenuItem,并将其附加到文件GtkMenuItem中。

$mb->append($filemi);

顶级GtkMenuItem被附加到GtkMenuBar小部件。

$vbox = new GtkVBox(false, 2);
$vbox->pack_start($mb, false, false, 0);

与其他工具包不同,我们必须自己照顾菜单栏的布局管理。 我们将菜单栏放入垂直框中。

Simple menu

图:简单菜单

子菜单

我们的最后一个示例演示了如何创建子菜单。 子菜单是另一个菜单中的菜单。

<?php

/* 
ZetCode PHP GTK tutorial

This example shows a submenu.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Submenu');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->modify_bg(Gtk::STATE_NORMAL, new GdkColor(6400, 6400, 6440));

        $mb = new GtkMenuBar();

        $filemenu = new GtkMenu();
        $filemi = new GtkMenuItem("File");
        $filemi->set_submenu($filemenu);

        $mb->append($filemi);

        $imenu = new GtkMenu();

        $importm = new GtkMenuItem("Import");
        $importm->set_submenu($imenu);

        $inews = new GtkMenuItem("Import news feed...");
        $ibookmarks = new GtkMenuItem("Import bookmarks...");
        $imail = new GtkMenuItem("Import mail...");

        $imenu->append($inews);
        $imenu->append($ibookmarks);
        $imenu->append($imail);

        $filemenu->append($importm);

        $exitmi = new GtkMenuItem("Exit");
        $exitmi->connect_simple('activate', array('gtk', 'main_quit'));

        $filemenu->append($exitmi);

        $vbox = new GtkVBox(false, 2);
        $vbox->pack_start($mb, false, false, 0);

        $this->add($vbox);

        $this->set_default_size(320, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

子菜单创建。

$imenu = new GtkMenu();

子菜单是常规GtkMenu

$importm = new GtkMenuItem("Import");
$importm->set_submenu($imenu);

它是菜单项的子菜单,它会登录到顶级文件菜单。

$inews = new GtkMenuItem("Import news feed...");
$ibookmarks = new GtkMenuItem("Import bookmarks...");
$imail = new GtkMenuItem("Import mail...");

$imenu->append($inews);
$imenu->append($ibookmarks);
$imenu->append($imail);

子菜单有其自己的菜单项。

Submenu

图:子菜单

图像菜单

在下一个示例中,我们将进一步探索菜单。 我们将图像和加速器添加到我们的菜单项中。 加速器是用于激活菜单项的键盘快捷键。

<?php

/* 
ZetCode PHP GTK tutorial

This example shows a menu with
images, accelerators and a separator.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Image menu');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->modify_bg(Gtk::STATE_NORMAL, new GdkColor(6400, 6400, 6440));

        $mb = new GtkMenuBar();

        $filemenu = new GtkMenu();
        $filemi = new GtkMenuItem("File");
        $filemi->set_submenu($filemenu);

        $mb->append($filemi);

        $agr = new GtkAccelGroup();
        $this->add_accel_group($agr);

        $newi = new GtkImageMenuItem(Gtk::STOCK_NEW, $agr);
        $newi->add_accelerator('activate', $agr, Gdk::KEY_N, 
             Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
        $newi->connect_simple('activate', array($this, 'on_new_selected')); 
        $filemenu->append($newi);

        $openmi = new GtkImageMenuItem(Gtk::STOCK_OPEN, $agr);
        $openmi->add_accelerator('activate', $agr, Gdk::KEY_O, 
             Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
        $filemenu->append($openmi);

        $sep = new GtkSeparatorMenuItem();
        $filemenu->append($sep);

        $exitmi = new GtkImageMenuItem(Gtk::STOCK_QUIT, $agr);
        $exitmi->add_accelerator('activate', $agr, Gdk::KEY_Q, 
             Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
        $exitmi->connect_simple('activate', array('gtk', 'main_quit'));     
        $filemenu->append($exitmi);       

        $vbox = new GtkVBox(false, 2);
        $vbox->pack_start($mb, false, false, 0);

        $this->add($vbox);

        $this->set_default_size(320, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_new_selected() {
        print "new";
    }

} 

new Example(); 
Gtk::main();

?>

我们的示例显示了具有三个子菜单项的顶级菜单项。 每个菜单项都有一个图像和一个加速器。 退出菜单项的加速器退出应用。 新菜单项的加速器将"new"打印到控制台。

$agr = new GtkAccelGroup();
$this->add_accel_group($agr);

要使用加速器,我们创建一个全局GtkAccelGroup对象。 稍后将使用。

$newi = new GtkImageMenuItem(Gtk::STOCK_NEW, $agr);
$newi->add_accelerator('activate', $agr, Gdk::KEY_N, 
      Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE);
$newi->connect_simple('activate', array($this, 'on_new_selected')); 
$filemenu->append($newi);

创建了GtkImageMenuItem。 图片来自图片库。 我们还创建了 Ctrl + N 加速器。 当我们用鼠标选择菜单项或按下加速器时,一条消息会打印到控制台上。

$sep = new GtkSeparatorMenuItem();
$filemenu->append($sep);

这些行创建一个分隔符。 它用于将菜单项放入逻辑组。

Image menu

图:图像 menu

菜单将我们可以在应用中使用的命令分组。 使用工具栏可以快速访问最常用的命令。

简单的工具栏

接下来,我们创建一个简单的工具栏。 工具栏提供对应用最常用功能的快速访问。

<?php

/* 
ZetCode PHP GTK tutorial

This example shows a toolbar widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Toolbar');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $toolbar = new GtkToolbar();
        $toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS);

        $newtb = GtkToolButton::new_from_stock(Gtk::STOCK_NEW);
        $opentb = GtkToolButton::new_from_stock(Gtk::STOCK_OPEN);
        $savetb = GtkToolButton::new_from_stock(Gtk::STOCK_SAVE);
        $sep = new GtkSeparatorToolItem();
        $quittb = GtkToolButton::new_from_stock(Gtk::STOCK_QUIT);

        $toolbar->insert($newtb, 0);
        $toolbar->insert($opentb, 1);
        $toolbar->insert($savetb, 2);
        $toolbar->insert($sep, 3);
        $toolbar->insert($quittb, 4);

        $quittb->connect_simple("clicked", array('Gtk', 'main_quit'));

        $vbox = new GtkVBox(false, 2);
        $vbox->pack_start($toolbar, false, false, 0);

        $this->add($vbox);

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }
} 

new Example(); 
Gtk::main();

?>

该示例显示了一个工具栏和四个工具按钮。

$toolbar = new GtkToolbar();

GtkToolbar小部件已创建。

$toolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS);

在工具栏上,我们仅显示图标。 没有文字。

$newtb = GtkToolButton::new_from_stock(Gtk::STOCK_NEW);

创建带有库存图像的GtkToolButton。 该图像来自图像的内置库存。

$sep = new GtkSeparatorToolItem();

这是一个分隔符。 它可用于将工具栏按钮放入逻辑组。

$toolbar->insert($newtb, 0);
$toolbar->insert($opentb, 1);
...

工具栏按钮插入到工具栏小部件中。 insert()方法的第一个参数是工具按钮。 第二个是工具栏上的位置。

Toolbar

图:工具栏

在 PHP GTK 教程的这一章中,我们展示了如何使用菜单和工具栏。

对话框

原文: http://zetcode.com/gui/phpgtktutorial/dialogs/

在 PHP GTK 编程教程的这一部分中,我们将介绍对话框。

对话框窗口或对话框是大多数现代 GUI 应用必不可少的部分。 对话被定义为两个或更多人之间的对话。 在计算机应用中,对话框是一个窗口,用于与应用“对话”。 对话框用于输入数据,修改数据,更改应用设置等。对话框是用户与计算机程序之间进行通信的重要手段。

GtkMessageDialog

消息对话框是方便的对话框,可向应用的用户提供消息。 该消息包含文本和图像数据。 GtkMessageDialog用于创建消息对话框。

<?php

/* 
ZetCode PHP GTK tutorial

This example demonstrates a
GtkMessageDialog.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('GtkMessageDialog');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();              

        $button = new GtkButton("Information");
        $button->set_size_request($button->size_request());
        $button->connect('clicked', array($this, 'on_clicked'));

        $fixed->put($button, 50, 50);
        $this->add($fixed); 

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_clicked($sender) {

            $md = new GtkMessageDialog($this, Gtk::DIALOG_MODAL,
                Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, "Download completed.");
            $md->set_title("Information");    
            $md->run();
            $md->destroy();
    }
} 

new Example(); 
Gtk::main();

?>

我们在窗口上显示一个按钮。 当我们单击按钮时,会显示一条信息消息。

$button = new GtkButton("Information");

这是一个按钮,当我们单击它时将显示一个对话框。

public function on_clicked($sender) {

        $md = new GtkMessageDialog($this, Gtk::DIALOG_MODAL,
            Gtk::MESSAGE_INFO, Gtk::BUTTONS_OK, "Download completed.");
        $md->set_title("Information");    
        $md->run();
        $md->destroy();
}

如果单击信息按钮,将显示“信息”对话框。 Gtk::DIALOG_MODAL标志使对话框变为模态。 Gtk::MESSAGE_INFO指定对话框的类型。 在我们的情况下,这是一个信息对话框。 为各种对话框类型选择了不同的图标。 Gtk::BUTTONS_OK在对话框上显示确定按钮。 最后一个参数是显示的消息。 我们使用set_title()方法设置对话框的标题。 该对话框使用run()方法显示。 程序员还必须最后调用destroy()hide()方法。

Information message dialog

图:信息消息对话框

GtkAboutDialog

GtkAboutDialog显示有关应用的信息。 它可以显示徽标,应用名称,版本,版权,网站或许可证信息。 也有可能对作者,文档撰写者,翻译者和艺术家予以赞扬。

<?php

/* 
ZetCode PHP GTK tutorial

This example demonstrates the
AboutDialog dialog.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('About Battery');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $fixed = new GtkFixed();              

        $button = new GtkButton("About");
        $button->set_size_request(80, 30);
        $button->connect('clicked', array($this, 'on_clicked'));

        $fixed->put($button, 50, 50);
        $this->add($fixed); 

        $this->set_default_size(250, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_clicked($sender) {

        $about = new GtkAboutDialog();
        $about->set_program_name("Battery");
        $about->set_version("0.1");
        $about->set_copyright("(c) Jan Bodnar");
        $about->set_comments("Battery is a simple tool for battery checking");
        $about->set_website("http://www.zetcode.com");
        $about->set_logo(GdkPixbuf::new_from_file("battery.png"));
        $about->run();
        $about->destroy();
    }

} 

new Example(); 
Gtk::main();

?>

该代码示例使用具有某些功能的GtkAboutDialog

$about = new GtkAboutDialog();

我们创建GtkAboutDialog的实例。

$about->set_program_name("Battery");
$about->set_version("0.1");
$about->set_copyright("(c) Jan Bodnar");

在这里,我们指定程序的名称,版本和版权。

$about->set_logo(GdkPixbuf::new_from_file("battery.png"));

此行创建徽标。

GtkAboutDialog

图:GtkAboutDialog

GtkFontSelectionDialog

GtkFontSelectionDialog是用于选择字体的对话框。 它通常用于进行一些文本编辑或格式化的应用中。

<?php

/* 
ZetCode PHP GTK tutorial

In this example, we change the font
of a label with the GtkFontSelectionDialog.

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

class Example extends GtkWindow { 

    private $label;

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('FontSelectionDialog');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->set_border_width(10);
        $this->label = new GtkLabel("The only victory over love is flight.");
        $button = new GtkButton("Select font");
        $button->connect('clicked', array($this, 'on_clicked'));

        $fixed = new GtkFixed();
        $fixed->put($button, 100, 30);
        $fixed->put($this->label, 30, 90);
        $this->add($fixed);

        $this->set_default_size(350, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_clicked($sender) {

        $fdia = new GtkFontSelectionDialog("Select font name");
        $response = $fdia->run();

        if ($response == Gtk::RESPONSE_OK) {

            $font_desc = new PangoFontDescription($fdia->get_font_name());
            print($fdia->get_font_name());
            if ($font_desc) {
                $this->label->modify_font($font_desc);
            }

        }

        $fdia->destroy();
    }
} 

new Example(); 
Gtk::main();

?>

在代码示例中,我们有一个按钮和一个标签。 单击按钮显示GtkFontSelectionDialog

$fdia = new GtkFontSelectionDialog("Select font name");

我们创建GtkFontSelectionDialog

if ($response == Gtk::RESPONSE_OK) {

    $font_desc = new PangoFontDescription($fdia->get_font_name());
    print($fdia->get_font_name());
    if ($font_desc) {
        $this->label->modify_font($font_desc);
    }

}

如果单击“确定”按钮,则标签小部件的字体将更改为我们在对话框中选择的字体。

GtkFontSelectionDialog

图:GtkFontSelectionDialog

GtkColorSelectionDialog

GtkColorSelectionDialog是用于选择颜色的对话框。

<?php

/* 
ZetCode PHP GTK tutorial

This example works with the
GtkColorSelectionDialog.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    private $label;

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('GtkColorSelectionDialog');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->set_border_width(10);
        $this->label = new GtkLabel("The only victory over love is flight.");
        $button = new GtkButton("Select color");
        $button->connect('clicked', array($this, 'on_clicked'));

        $fixed = new GtkFixed();
        $fixed->put($button, 100, 30);
        $fixed->put($this->label, 30, 90);
        $this->add($fixed);

        $this->set_default_size(350, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_clicked($sender) {

        $cdia = new GtkColorSelectionDialog("Select color");
        $response = $cdia->run();

        if ($response == Gtk::RESPONSE_OK) {
            $colorsel = $cdia->colorsel;
            $color = $colorsel->get_current_color();
            $this->label->modify_fg(Gtk::STATE_NORMAL, $color);
        }

        $cdia->destroy();
    }
} 

new Example(); 
Gtk::main();

?>

该示例与上一个示例非常相似。 这次我们更改标签的颜色。

$cdia = new GtkColorSelectionDialog("Select color");
$response = $cdia->run();

我们创建并运行GtkFontSelectionDialog

if ($response == Gtk::RESPONSE_OK) {
    $colorsel = $cdia->colorsel;
    $color = $colorsel->get_current_color();
    $this->label->modify_fg(Gtk::STATE_NORMAL, $color);
}

如果用户按下 OK,我们将获得颜色值并修改标签的颜色。

在 PHP GTK 教程的这一部分中,我们介绍了对话框。

Cario 绘图

原文: http://zetcode.com/gui/phpgtktutorial/cairo/

在 PHP GTK 教程的这一部分中,我们将使用 Cairo 库进行一些绘图。 目前,Seed 仅支持 Cario 库的一小部分。

Cairo 是用于创建 2D 矢量图形的库。 我们可以使用它来绘制自己的小部件,图表或各种效果或动画。

Cairo for PHP 是与 PHP GTK 分开的项目。 除了 PHP GTK,我们还需要安装 Cairo。 在构建库之前,我们必须在系统上安装libcairo2-dev包。

svn co http://svn.php.net/repository/pecl/cairo/trunk cairo
cd cairo/
$ phpize5
$ ./configure 
$ make
$ make install

在创建本教程时,以上命令用于为 PHP 安装 Cairo。

最后,在安装 Cairo 之后,我们需要为我们的 PHP 脚本启用 Cairo 库。

$ sudo vi /etc/php5/cli/php.ini 

;;;;;;;;;;;;;;;;;;;;;;
; Dynamic Extensions ;
;;;;;;;;;;;;;;;;;;;;;;

;
extension=php_gtk2.so
extension=cairo.so

我们编辑php.ini文件并添加 Cairo 动态扩展。

色彩

在第一个示例中,我们将处理颜色。 颜色是代表红色,绿色和蓝色(RGB)强度值的组合的对象。 Cario 有效 RGB 值在 0 到 1 的范围内。

<?php

/* 
ZetCode PHP GTK tutorial

In this program, we will draw three
colored rectangles on the drawing area
using Cairo.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Colors');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 

        $this->add($darea);    

        $this->set_default_size(360, 100); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

            $cr = $darea->window->cairo_create();
            $this->draw_colors($cr);        

    }

    public function draw_colors($cr) {

        $cr->setSourceRgb(0.2, 0.23, 0.9);
        $cr->rectangle(10, 15, 90, 60);
        $cr->fill();

        $cr->setSourceRgb(0.9, 0.1, 0.1);
        $cr->rectangle(130, 15, 90, 60);
        $cr->fill();

        $cr->setSourceRgb(0.4, 0.9, 0.4);
        $cr->rectangle(250, 15, 90, 60);
        $cr->fill();            
    }   
} 

new Example(); 
Gtk::main();

?>

在我们的示例中,我们将绘制三个矩形,并用三种不同的颜色填充它们。

$darea = new GtkDrawingArea();

我们将在GtkDrawingArea小部件上进行绘制操作。

$darea->connect('expose_event', array($this, 'on_expose')); 

当需要重绘窗口时,将触发expose_event。 为响应此事件,我们调用on_expose()方法。

$cr = $darea->window->cairo_create();

我们从绘图区域的GdkWindow创建 cairo 上下文对象。 上下文是我们绘制所有图纸的对象。

$this->draw_colors($cr);   

实际图形委托给draw_colors()方法。

$cr->setSourceRgb(0.2, 0.23, 0.9);

setSourceRgb()方法为 Cario 上下文设置颜色。 该方法的三个参数是颜色强度值。

$cr->rectangle(10, 15, 90, 60);

我们画一个矩形。 前两个参数是矩形左上角的 x,y 坐标。 最后两个参数是矩形的宽度和高度。

$cr->fill();

我们用当前颜色填充矩形的内部。

Colors

图:颜色

基本形状

下一个示例将一些基本形状绘制到窗口上。

<?php

/* 
ZetCode PHP GTK tutorial

This code example draws basic shapes
with the Cairo library.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Basic shapes');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 

        $this->add($darea);    

        $this->set_default_size(390, 240); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

        $cr = $darea->window->cairo_create();
        $this->draw_shapes($cr);        

    }

    public function draw_shapes($cr) {

        $cr->SetSourceRgb(0.6, 0.6, 0.6);

        $cr->rectangle(20, 20, 120, 80);
        $cr->rectangle(180, 20, 80, 80);
        $cr->fill();

        $cr->arc(330, 60, 40, 0, 2*M_PI);
        $cr->fill();

        $cr->arc(90, 160, 40, M_PI/4, M_PI);
        $cr->fill();

        $cr->translate(220, 180);
        $cr->scale(1, 0.7);
        $cr->arc(0, 0, 50, 0, 2*M_PI);
        $cr->fill();          
    }   
} 

new Example(); 
Gtk::main();

?>

在此示例中,我们将创建一个矩形,一个正方形,一个圆形,一个弧形和一个椭圆形。 我们用蓝色绘制轮廓,内部用白色绘制。

$cr->rectangle(20, 20, 120, 80);
$cr->rectangle(180, 20, 80, 80);
$cr->fill();

这些线绘制一个矩形和一个正方形。

$cr->arc(330, 60, 40, 0, 2*M_PI);
$cr->fill();

此处arc()方法绘制一个完整的圆。

$cr->translate(220, 180);
$cr->scale(1, 0.7);
$cr->arc(0, 0, 50, 0, 2*M_PI);
$cr->fill();  

translate()方法将对象移动到特定点。 如果要绘制椭圆形,请先进行一些缩放。 在这里scale()方法缩小 y 轴。

Basic shapes

图:基本形状

透明矩形

透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。

在计算机图形学中,我们可以使用 alpha 合成来实现透明效果。 Alpha 合成是将图像与背景组合以创建部分透明外观的过程。 合成过程使用 Alpha 通道。 (wikipedia.org,answers.com)

<?php

/* 
ZetCode PHP GTK tutorial

This code example draws nine rectangles
with different levels of transparency.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Transparent rectangles');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 

        $this->add($darea);    

        $this->set_default_size(590, 90); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

        $cr = $darea->window->cairo_create();
        $this->draw_recs($cr);        

    }

    public function draw_recs($cr) {

        for ($i=1; $i<=10; $i++) {
            $cr->SetSourceRgba(0, 0, 1, $i*0.1);
            $cr->rectangle(50*$i, 20, 40, 40);
            $cr->fill();
        }     
    }   
} 

new Example(); 
Gtk::main();

?>

在示例中,我们将绘制十个具有不同透明度级别的矩形。

$cr->SetSourceRgba(0, 0, 1, $i*0.1);

set_source_rgba()方法的最后一个参数是 alpha 透明度。

Transparent rectangles

图:透明矩形

甜甜圈

在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。


<?php

/* 
ZetCode PHP GTK tutorial

In this program, we draw a donut shape
by rotating a bunch of ellipses. 

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Donut');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 

        $this->add($darea);    

        $this->set_default_size(350, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

            $cr = $darea->window->cairo_create();
            $this->draw_donut($cr);        

    }

    public function draw_donut($cr) {

        $cr->SetLineWidth(0.5);

        $w = $this->get_allocation()->width;
        $h = $this->get_allocation()->height;

        $cr->translate($w/2, $h/2);
        $cr->arc(0, 0, 120, 0, 2*M_PI);
        $cr->stroke();

        for ($i=1; $i<=36; $i++) {
            $cr->save();
            $cr->rotate($i*M_PI/36);
            $cr->scale(0.3, 1);
            $cr->arc(0, 0, 120, 0, 2*M_PI);
            $cr->restore();
            $cr->stroke();
        }
    }   
} 

new Example(); 
Gtk::main();

?>

在此示例中,我们创建一个甜甜圈。 形状类似于曲奇,因此得名“甜甜圈”。

$cr->translate($w/2, $h/2);
$cr->arc(0, 0, 120, 0, 2*M_PI);
$cr->stroke();

刚开始时有一个椭圆。

for ($i=1; $i<=36; $i++) {
    $cr->save();
    $cr->rotate($i*M_PI/36);
    $cr->scale(0.3, 1);
    $cr->arc(0, 0, 120, 0, 2*M_PI);
    $cr->restore();
    $cr->stroke();
}

旋转几圈后,有一个甜甜圈。

绘制文字

在下一个示例中,我们在窗口上绘制一些文本。

<?php

/* 
ZetCode PHP GTK tutorial

In this program, we draw text on the
window. 

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    public function init_ui() {

        $this->set_title('Soulmate');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $darea = new GtkDrawingArea();
        $darea->connect('expose_event', array($this, 'on_expose')); 

        $this->add($darea);    

        $this->set_default_size(350, 250); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_expose($darea, $event) {

            $cr = $darea->window->cairo_create();
            $this->draw_text($cr);        

    }

    public function draw_text($cr) {

        $cr->SetSourceRgb(0.1, 0.1, 0.1);

        $cr->SelectFontFace("Purisa", CairoFontSlant::NORMAL, 
            CairoFontWeight::NORMAL);
        $cr->SetFontSize(13);

        $cr->MoveTo(20, 30);
        $cr->ShowText("Most relationships seem so transitory");
        $cr->MoveTo(20, 60);
        $cr->ShowText("They're all good but not the permanent one");
        $cr->MoveTo(20, 120);
        $cr->ShowText("Who doesn't long for someone to hold");
        $cr->MoveTo(20, 150);
        $cr->ShowText("Who knows how to love without being told");
        $cr->MoveTo(20, 180);
        $cr->ShowText("Somebody tell me why I'm on my own");
        $cr->MoveTo(20, 210);
        $cr->ShowText("If there's a soulmate for everyone");
    }   
} 

new Example(); 
Gtk::main();

?>

我们显示 Natasha Bedingfields Soulmate 歌曲的部分歌词。

$cr->SelectFontFace("Purisa", CairoFontSlant::NORMAL, 
    CairoFontWeight::NORMAL);

在这里,我们指定使用的字体。 Purisa 正常字体。

$cr->SetFontSize(13);

我们指定字体的大小。

$cr->MoveTo(20, 30);

我们移动到要绘制文本的位置。

$cr->ShowText("Most relationships seem so transitory");

ShowText()方法将文本绘制到窗口上。

Soulmate

图:灵魂伴侣

在 PHP GTK 教程的这一章中,我们使用 Cairo 库进行绘图。

自定义小部件

原文: http://zetcode.com/gui/phpgtktutorial/customwidget/

工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 如果需要更专业的小部件,我们必须自己创建它。

使用工具箱提供的绘图工具创建自定义窗口小部件。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。

刻录小部件

这是我们从头开始创建的小部件的示例。 它基于最小的GtkWidget小部件。 可以在各种媒体刻录应用(例如 Nero Burning ROM)中找到此自定义窗口小部件。

<?php

/* 
ZetCode PHP GTK tutorial

This example creates a burning
custom widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: August 2011
*/

class Burning extends GtkDrawingArea { 

    public function __construct($par) { 

        parent::__construct(); 

        $this->par = $par;          

        $this->init_ui();

    } 

    public function init_ui() {

        $this->num = array("75", "150", "225", "300", 
            "375", "450", "525", "600", "675");

        $this->set_size_request(1, 30);
        $this->connect('expose_event', array($this, 'on_expose')); 

    }

    public function on_expose() {
        $cr = $this->window->cairo_create();
        $this->draw_widget($cr);
    }

    public function draw_widget($cr) {

        $cr->SetLineWidth(0.8);
        $cr->SelectFontFace("Courier", CairoFontSlant::NORMAL, 
            CairoFontWeight::NORMAL);
        $cr->SetFontSize(11);

        $width = $this->get_allocation()->width;

        $this->cur_width = $this->par->get_cur_value();

        $step = round($width / 10.0);

        $till = ($width / 750.0) * $this->cur_width;
        $full = ($width / 750.0) * 700;

        if ($this->cur_width >= 700) {

            $cr->SetSourceRgb(1.0, 1.0, 0.72);
            $cr->Rectangle(0, 0, $full, 30);
            $cr->Clip();
            $cr->Paint();
            $cr->ResetClip();

            $cr->SetSourceRgb(1.0, 0.68, 0.68).
            $cr->Rectangle($full, 0, $till-$full, 30);
            $cr->Clip();
            $cr->Paint();
            $cr->ResetClip();

        } else {
            $cr->SetSourceRgb(1.0, 1.0, 0.72);
            $cr->Rectangle(0, 0, $till, 30);
            $cr->Clip();
            $cr->Paint();
            $cr->ResetClip();
        }

        $cr->SetSourceRgb(0.35, 0.31, 0.24);
        $len = count($this->num);

        for ($i=1; $i <= $len; $i++) {
            $cr->MoveTo($i*$step, 0);
            $cr->LineTo($i*$step, 5);
            $cr->Stroke();

            $te = $cr->TextExtents($this->num[$i-1]);
            $cr->MoveTo($i*$step-$te['width']/2, 15);
            $cr->TextPath($this->num[$i-1]);
            $cr->Stroke();
        }        
    }
}

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('Burning widget');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->cur_value = 0;

        $vbox = new GtkVBox(false, 2);

        $scale = new GtkHScale();
        $scale->set_range(0, 750);
        $scale->set_digits(0);
        $scale->set_size_request(160, 35);
        $scale->set_value($this->cur_value);

        $scale->connect('value-changed', array($this, 'on_changed'));

        $fixed = new GtkFixed();
        $fixed->put($scale, 50, 50);

        $vbox->pack_start($fixed);

        $this->burning = new Burning($this);
        $vbox->pack_start($this->burning, false, false, 0);

        $this->add($vbox);

        $this->set_default_size(350, 200); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_changed($sender) {

        $this->cur_value = $sender->get_value();
        $this->burning->queue_draw();
    }

    public function get_cur_value() {
        return $this->cur_value;
    }
} 

new Example(); 
Gtk::main();

?>

我们在窗口底部放置一个GtkDrawingArea并手动绘制整个窗口小部件。 所有重要的代码都驻留在draw_widget()中,这是从 Burning 类的on_expose()方法调用的。 此小部件以图形方式显示了介质的总容量和可供我们使用的可用空间。 该小部件由比例小部件控制。 自定义窗口小部件的最小值为 0,最大值为 750。如果值达到 700,则开始绘制红色。 这通常表示过度燃烧。

$this->num = array("75", "150", "225", "300", 
    "375", "450", "525", "600", "675");

这些数字显示在刻录小部件上。 它们显示了介质的容量。

$this->cur_width = $this->par->get_cur_value();

从父小部件中,我们获得了比例小部件的当前值。

$till = ($width / 750.0) * $this->cur_width;
$full = ($width / 750.0) * 700;

我们使用$width变量进行转换。 在比例尺值和自定义小部件的度量之间。 请注意,我们使用浮点值。 我们在绘图中获得了更高的精度。 $till参数确定要绘制的总大小。 该值来自滑块小部件。 它占整个面积的一部分。 $full参数确定了我们开始绘制红色的点。

$cr->SetSourceRgb(1.0, 1.0, 0.72);
$cr->Rectangle(0, 0, $full, 30);
$cr->Clip();
$cr->Paint();
$cr->ResetClip();

我们绘制一个黄色矩形,直到介质充满为止。

$te = $cr->TextExtents($this->num[$i-1]);
$cr->MoveTo($i*$step-$te['width']/2, 15);
$cr->TextPath($this->num[$i-1]);
$cr->Stroke();

这里的代码在刻录小部件上绘制数字。 我们计算文本范围以正确定位文本。

public function on_changed($sender) {

    $this->cur_value = $sender->get_value();
    $this->burning->queue_draw();
}

我们从小部件中获取值,并将其存储在$this->cur_value变量中以备后用。 我们重新绘制刻录的小部件。

Burning widget

图:刻录小部件

在本章中,我们使用 GTK 和 PHP 编程语言创建了一个自定义窗口小部件。

贪食蛇

原文: http://zetcode.com/gui/phpgtktutorial/nibbles/

在 PHP GTK 编程教程的这一部分中,我们将创建一个贪食蛇游戏克隆。

贪食蛇是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。

开发

蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 游戏结束后,我们在窗口中心显示"Game Over"消息。

该代码分为两个文件。 board.phpnibbles.php

<?php

// board.php

define("WIDTH", 300);
define("HEIGHT", 270);
define("DOT_SIZE", 10);
define("ALL_DOTS", WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE));
define("RAND_POS", 26);

class Board extends GtkDrawingArea {

    public function __construct() { 

        parent::__construct(); 

        $this->modify_bg(Gtk::STATE_NORMAL, new GdkColor(6400, 6400, 6440));

        $this->connect('expose_event', array($this, 'on_expose')); 

        $this->init_game();

    } 

    public function init_game() {

        $this->x = array_fill(0, ALL_DOTS, 0);
        $this->y = array_fill(0, ALL_DOTS, 0);

        $this->left = false;
        $this->right = true;
        $this->up = false;
        $this->down = false;
        $this->inGame = true;
        $this->dots = 3;

        for ($i=0; $i<=$this->dots; $i++) {
            $this->x[$i] = 50 - $i * 10;
            $this->y[$i] = 50;
        }

        try {
            $this->dot = CairoImageSurface::createFromPng("dot.png");
            $this->head = CairoImageSurface::createFromPng("head.png");
            $this->apple = CairoImageSurface::createFromPng("apple.png");
        } catch( Exception  $e) {
            echo $e->getMessage();
            echo "cannot load images";
            exit;
        }

        $this->locate_apple();
        $this->set_can_focus(true);

        Gtk::timeout_add(100, array($this, 'on_timer'));

     }

    public function on_timer() {

        if ($this->inGame) {
            $this->check_apple();
            $this->check_collision();
            $this->move();
            $this->queue_draw();
            return true;
        } else {
            return false;
        }
    }

    public function on_expose() {

        $cr = $this->window->cairo_create();

        if ($this->inGame) {
            $this->draw_objects($cr);
        } else {
            $this->game_over($cr);
        }
    }

    public function draw_objects($cr) {

        $cr->SetSourceRgb(0, 0, 0);
        $cr->paint();

        $cr->setSourceSurface($this->apple, 
            $this->apple_x, $this->apple_y);
        $cr->paint();

        for ($z=0; $z<=$this->dots; $z++) {
            if ($z == 0) {
                $cr->setSourceSurface($this->head, 
                    $this->x[$z], $this->y[$z]);
                $cr->paint();
            } else {
                $cr->setSourceSurface($this->dot, 
                    $this->x[$z], $this->y[$z]);
                $cr->paint();
            } 
        }
    }

    public function game_over($cr) {

        $c_x = $this->get_allocation()->width/2;
        $c_y = $this->get_allocation()->height/2;

        $cr->SetFontSize(15);
        $cr->SetSourceRgb(65535, 65535, 65535);

        $te = $cr->TextExtents("Game Over");

        $cr->MoveTo($c_x - $te['width']/2, $c_y);
        $cr->ShowText("Game Over");
    }

    public function check_apple() {

        if ($this->x[0] == $this->apple_x 
                and $this->y[0] == $this->apple_y) {
            $this->dots = $this->dots + 1;
            $this->locate_apple();
        }
    }

    public function move() {

        $z = $this->dots;

        while ($z > 0) {
            $this->x[$z] = $this->x[($z - 1)];
            $this->y[$z] = $this->y[($z - 1)];
            $z--;
        }

        if ($this->left) {
            $this->x[0] -= DOT_SIZE;
        }

        if ($this->right) {
            $this->x[0] += DOT_SIZE;
        }

        if ($this->up) {
            $this->y[0] -= DOT_SIZE;
        }

        if ($this->down) {
            $this->y[0] += DOT_SIZE;
        }

     }

    public function check_collision() {

        $z = $this->dots;

        while ($z > 0) {
            if ($z > 4 and $this->x[0] == $this->x[$z] 
                       and $this->y[0] == $this->y[$z]) {
                $this->inGame = false;
            }
            $z--;
        }

        if ($this->y[0] > HEIGHT - DOT_SIZE) {
            $this->inGame = false;
        }

        if ($this->y[0] < 0) {
            $this->inGame = false;
        }

        if ($this->x[0] > WIDTH - DOT_SIZE) {
            $this->inGame = false;
        }

        if ($this->x[0] < 0) {
            $this->inGame = false;
        }

    }

    public function locate_apple() {

        $r = rand(0, RAND_POS);
        $this->apple_x = $r * DOT_SIZE;
        $r = rand(0, RAND_POS);
        $this->apple_y = $r * DOT_SIZE;
    }

    public function on_key_down($event) {

        $key = $event->keyval;

        if ($key == Gdk::KEY_Left and !$this->right) {
            $this->left = true;
            $this->up = false;
            $this->down = false;
        }

        if ($key == Gdk::KEY_Right and !$this->left) {
            $this->right = true;
            $this->up = false;
            $this->down = false;
        }

        if ($key == Gdk::KEY_Up and !$this->down) {
            $this->up = true;
            $this->right = false;
            $this->left = false;
        }

        if ($key == Gdk::KEY_Down and !$this->up) {
            $this->down = true;
            $this->right = false;
            $this->left = false;
        }
    }
}
?>

这是 board.php 文件。

define("WIDTH", 300);
define("HEIGHT", 270);
define("DOT_SIZE", 10);
define("ALL_DOTS", WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE));
define("RAND_POS", 26);

WIDTHHEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。

$this->x = array_fill(0, ALL_DOTS, 0);
$this->y = array_fill(0, ALL_DOTS, 0);

这两个数组存储蛇的所有可能关节的 x,y 坐标。

init_game()方法初始化变量,加载图像并启动超时功能。

if ($this->inGame) {
    $this->check_apple();
    $this->check_collision();
    $this->move();
    $this->queue_draw();
    return true;
} else {
    return false;
}

每 140 毫秒,将调用on_timer()方法。 如果我们参与了游戏,我们将调用三种构建游戏逻辑的方法。 queue_draw()方法强制重新绘制窗口小部件。 这将反映游戏板上的变化。 否则,我们返回false,它将停止计时器事件。

$cr = $this->window->cairo_create();

if ($this->inGame) {
    $this->draw_objects($cr);
} else {
    $this->game_over($cr);
}    

on_expose()方法内部,我们检查$this->inGame变量。 如果为真,则绘制对象。 苹果和蛇的关节。 否则,我们显示"Game Over"文本。

public function draw_objects($cr) {

    $cr->SetSourceRgb(0, 0, 0);
    $cr->paint();

    $cr->setSourceSurface($this->apple, 
        $this->apple_x, $this->apple_y);
    $cr->paint();

    for ($z=0; $z<=$this->dots; $z++) {
        if ($z == 0) {
            $cr->setSourceSurface($this->head, 
                $this->x[$z], $this->y[$z]);
            $cr->paint();
        } else {
            $cr->setSourceSurface($this->dot, 
                $this->x[$z], $this->y[$z]);
            $cr->paint();
        } 
    }
}

draw_objects()方法绘制苹果和蛇的关节。 蛇的第一个关节是其头部,用红色圆圈表示。

如果游戏结束,则调用game_over()方法。 此方法在窗口中心显示"Game Over"

$c_x = $this->get_allocation()->width/2;
$c_y = $this->get_allocation()->height/2;

在这里,我们获得窗口的中心点。

$cr->SetFontSize(15);
$cr->SetSourceRgb(65535, 65535, 65535);

我们设置文本的字体大小和颜色。 背景为黑色,因此字体将为白色。

$te = $cr->TextExtents("Game Over");

我们得到字符串的文本范围。 为了将文本放置在窗口的中央,这是必需的。

$cr->MoveTo($c_x - $te['width']/2, $c_y);
$cr->ShowText("Game Over");

我们移到中心并显示文本。

public function check_apple() {

    if ($this->x[0] == $this->apple_x 
            and $this->y[0] == $this->apple_y) {
        $this->dots = $this->dots + 1;
        $this->locate_apple();
    }
}

check_apple()方法检查蛇是否击中了苹果对象。 如果是这样,我们添加另一个蛇形关节并调用locate_apple()方法,该方法将随机放置一个新的Apple对象。

move()方法中,我们有游戏的关键算法。 要了解它,请看一下蛇是如何运动的。 您控制蛇的头。 您可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。

while ($z > 0) {
    $this->x[$z] = $this->x[($z - 1)];
    $this->y[$z] = $this->y[($z - 1)];
    $z--;
}

该代码将关节向上移动。

if ($this->left) {
    $this->x[0] -= DOT_SIZE;
}

将头向左移动。

check_collision()方法中,我们确定蛇是否击中了自己或撞墙之一。

while ($z > 0) {
    if ($z > 4 and $this->x[0] == $this->x[$z] 
                and $this->y[0] == $this->y[$z]) {
        $this->inGame = false;
    }
    $z--;
}

如果蛇用头撞到关节之一,我们就结束游戏。

if ($this->y[0] > HEIGHT - DOT_SIZE) {
  $this->inGame = false;
}

如果蛇击中了棋盘的底部,我们就结束了游戏。

locate_apple()方法在板上随机放置一个苹果。

$r = rand(0, RAND_POS);

我们得到一个从 0 到RAND_POS-1的随机数。

$this->apple_x = $r * DOT_SIZE;
...
$this->apple_y = $r * DOT_SIZE;

这些行设置了apple对象的 x,y 坐标。

Board类的on_key_down()方法中,我们确定按下的键。

if ($key == Gdk::KEY_Left and !$this->right) {
    $this->left = true;
    $this->up = false;
    $this->down = false;
}

如果单击左光标键,则将$this->left变量设置为 true。 在move()方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。

<?php

/* 
ZetCode PHP GTK tutorial

In this program, we create a Nibbles
game clone. 

author: Jan Bodnar
website: www.zetcode.com
last modified: September 2011
*/

include 'board.php';

class Example extends GtkWindow { 

    public function __construct() { 

        parent::__construct(); 

        $this->init_ui();

    } 

    private function init_ui() {

        $this->set_title('Nibbles');         
        $this->connect_simple('destroy', array('gtk', 'main_quit')); 

        $this->board = new Board();
        $this->board->connect('key-press-event', array($this, 'on_key_down'));

        $this->add($this->board);

        $this->set_default_size(300, 270); 
        $this->set_position(GTK::WIN_POS_CENTER);
        $this->show_all();         
    }

    public function on_key_down($sender, $event) {

        $key = $event->keyval;
        $this->board->on_key_down($event);
    }
} 

new Example(); 
Gtk::main();

?>

这是nibbles.php文件。 在此文件中,我们设置了贪食蛇游戏。

public function on_key_down($sender, $event) {

    $key = $event->keyval;
    $this->board->on_key_down($event);
}

在这个类中,我们捕获按键事件。 并将处理委托给板类的on_key_down()方法。

Nibbles

图:贪食蛇

这是用 GTK 库和 PHP 编程语言编程的贪食蛇电脑游戏。

C# Qyoto 教程

原文: http://zetcode.com/gui/csharpqyoto/

这是 C# Qyoto 编程教程。 Qyoto 是 Qt 库与 C# 和其他 .NET 语言的绑定。 Qyoto C# 教程适合初学者和中级程序员。

目录

Qyoto

Qyoto 是一个库,它提供 Qt 库与.NET 语言(如 C# 或 Visual Basic)的绑定。 Qt 是功能强大的跨平台应用开发框架。 它的母语是 C++ 。 Qyoto 是 KDE 桌面环境的一部分。

C#

C# 是一种现代的,高级的,通用的,面向对象的编程语言。 它是.NET 框架的主要语言。 该语言的设计目标是软件健壮性,耐用性和程序员生产率。 它可用于在 PC 或嵌入式系统上创建控制台应用,GUI 应用,Web 应用。

相关教程

C# 教程涵盖了 C# 语言。 GTK# 教程提供了 C# 绑定到 GTK 库的教程。 Mono C# Winforms 教程是使用 Winforms 库和 C# 语言对 GUI 应用进行编程的教程。 最后, Visual Basic Qyoto 教程是使用 Visual Basic 开发 Qyoto 应用的教程。

Qyoto 介绍

原文: http://zetcode.com/gui/csharpqyoto/introduction/

在 Qyoto C# 编程教程的这一部分中,我们将介绍并构建 Qyoto 库。 我们使用 C# 编程语言创建第一个 Qyoto 程序。

本教程的目的是帮助您开始使用 Qyoto 和 C# 。 可以在此处下载本教程中使用的图像。 我使用了 Gnome 项目的探戈图标包中的一些图标。 该教程是在 Qyoto 项目的维护者 Dimitar Dobrev 的帮助下创建的。

关于

Qyoto 是一个库,它提供 Qt 库与.NET 语言(如 C# 或 Visual Basic)的绑定。 Qt 是功能强大的跨平台应用开发框架。 它的母语是 C++ 。 Qyoto 是 KDE 桌面环境的一部分。 Qyoto 是使用SMOKE库创建的。 这是一个 KDE 项目,用于创建多种语言的绑定。 SMOKE 代表脚本元对象 Kompiler 引擎。

在 Linux 上构建 Qyoto

我们从最新资源构建 Qyoto 库。

$ git clone git://anongit.kde.org/smokegen
$ git clone git://anongit.kde.org/smokeqt
$ git clone git://anongit.kde.org/assemblygen

我们从 git 仓库下载源代码。

$ sudo apt-get install cmake-qt-gui

如果不存在,请安装cmake-qt-gui

我们按以下顺序构建三个包:1)smokegen,2)smokeqt 和 3)assemblygen。 我们在三个目录中的每个目录中运行cmake-qt-gui。 我们指定源,构建目录,并将CMAKE_BUILD_TYPE设置为Release。 我们单击配置和生成按钮。 将目录更改为构建目录。 运行makesudo make install

$ export LD_LIBRARY_PATH=/usr/local/qt4/lib

在构建smokeqt包之前,我们设置一个环境变量。 每次构建后,我们运行sudo ldconfig命令。

$ ls /usr/local/lib/mono/qyoto 
qyoto-qtcore.dll  qyoto-qtsvg.dll
qtscript.dll      qyoto-qtgui.dll      qyoto-qtuitools.dll
qttest.dll        qyoto-qtnetwork.dll  qyoto-qtwebkit.dll
qtuitools.dll     qyoto-qtopengl.dll   qyoto-qtxml.dll
qtwebkit.dll      qyoto-qtscript.dll   qyoto-qtxmlpatterns.dll
qyoto-phonon.dll  qyoto-qtsql.dll

我们在/usr/local/lib/mono/qyoto目录中有 Qyoto dll。

$ dmcs -r:/usr/local/lib/mono/qyoto/qyoto-qtcore.dll \
> -r:/usr/local/lib/mono/qyoto/qyoto-qtgui.dll donut.cs

上面的命令显示了如何编译甜甜圈示例。 mono C# 编译器的-r参数加载 Qt 程序集。 这是一个动态库。 该命令显示 Linux 系统上 dll 库的路径。

创建工具提示

第一个示例将显示一个工具提示。 工具提示是一个小的矩形窗口,它提供有关对象的简短信息。 它通常是一个 GUI 组件。 它是应用帮助系统的一部分。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program displays a
 * tooltip.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "Tooltip";

        ToolTip = "This is QWidget";    
        Resize(250, 150);
        Move(300, 300);
        Show();
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

该示例创建一个窗口。 如果将鼠标指针悬停在窗口区域上方,则会弹出一个工具提示。

using System;
using QtCore;
using QtGui;

using关键字导入我们将在应用中使用的必需品类型。

public class QyotoApp : QWidget {

该示例继承自QWidget。 QWidget 类是所有用户界面对象的基类。 小部件是用户界面的原子。 它从窗口系统接收鼠标,键盘和其他事件。

WindowTitle = "Tooltip";

设置WindowType属性将显示窗口的标题。

ToolTip = "This is QWidget";

我们通过ToolTip属性设置工具提示。

Resize(250, 150);

在这里,我们设置窗口的宽度和高度。

Move(300, 300);

Move()方法在屏幕上移动窗口。

Show();

一切准备就绪后,我们在屏幕上显示窗口。

[STAThread]
public static int Main(String[] args) 

Windows 平台上需要[STAThread]属性。 确保与 COM 组件的通信是安全的。 在某些情况下,例如剪贴板和文件对话框,我们正在调用 COM 组件。 没有此属性,应用将崩溃。

new QApplication(args);
new QyotoApp();
return QApplication.Exec();

这三行设置了应用。

Tooltip

图:工具提示

使窗口居中

在第二个示例中,我们将窗口置于屏幕中央。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program centers a window
 * on the screen.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    const int WIDTH = 250;
    const int HEIGHT = 150;

    public QyotoApp() 
    {
        WindowTitle = "Center";

        Resize(WIDTH, HEIGHT);
        Center();
        Show();
    }

    private void Center()
    {
        QDesktopWidget qdw = new QDesktopWidget();

        int screenWidth = qdw.Width;
        int screenHeight = qdw.Height;

        int cx = (screenWidth - WIDTH) / 2;
        int cy = (screenHeight - HEIGHT) / 2;        

        Move(cx, cy);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

Qyoto 没有使窗口居中的单一方法。

const int WIDTH = 250;
const int HEIGHT = 150;

这两个常数定义了应用窗口的宽度和高度。

Center();

使窗口居中的代码位于Center()方法中。

QDesktopWidget qdw = new QDesktopWidget();

QDesktopWidget类提供有关屏幕的信息。

int screenWidth = qdw.Width();
int screenHeight = qdw.Height();

在这里,我们确定屏幕的宽度和高度。

int cx = (screenWidth - WIDTH) / 2;
int cy = (screenHeight - HEIGHT) / 2;  

在这里,我们计算居中窗口的 x,y 坐标。 为了使窗口在屏幕上居中,我们需要知道屏幕的大小和窗口的大小。

Move(cx, cy);

我们将窗口移至计算出的cxcy坐标。

退出按钮

在本节的最后一个示例中,我们将创建一个退出按钮。 当我们按下此按钮时,应用终止。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program creates a quit
 * button. When we press the button,
 * the application terminates. 
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "Quit button";

        InitUI();

        Resize(250, 150);
        Move(300, 300);
        Show();
    }

    public void InitUI() 
    {    
        QPushButton quit = new QPushButton("Quit", this);

        Connect(quit, SIGNAL("clicked()"), qApp, SLOT("quit()"));
        quit.SetGeometry(50, 40, 80, 30);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们使用QPushButton。 它是矩形的,通常显示一个文本标签。

InitUI();

我们将用户界面的创建委托给InitUI()方法。

QPushButton quit = new QPushButton("Quit", this);

我们创建按钮小部件。 构造器的第一个参数是标签,按钮将显示该标签。 第二个参数是按钮的父窗口小部件。

Connect(quit, SIGNAL("clicked()"), qApp, SLOT("quit()"));

当我们点击按钮时,会发出clicked()信号。 Connect()方法将信号连接到对象的特定槽。 该方法的第一个参数是接收信号的对象。 在我们的例子中,它是应用对象。 第二个参数是方法,称为。 在我们的情况下,它是应用对象的quit()方法。 qApp是对应用对象的全局引用。

quit.SetGeometry(50, 40, 80, 30);

我们定位和调整按钮小部件的大小。 前两个参数是按钮的 x,y 坐标。 最后两个参数是按钮的宽度和高度。

Quit button

图:退出按钮

本节介绍了使用 C# 语言编写的 Qyoto 库。

PyQt5 拖放

原文: http://zetcode.com/gui/pyqt5/dragdrop/

在 PyQt5 教程的这一部分中,我们将讨论拖放操作。

在计算机图形用户界面中,拖放是单击虚拟对象并将其拖动到其他位置或另一个虚拟对象上的动作(或支持以下动作)。 通常,它可用于调用多种动作,或在两个抽象对象之间创建各种类型的关联。

拖放是图形用户界面的一部分。 拖放操作使用户可以直观地执行复杂的操作。

通常,我们可以拖放两件事:数据或某些图形对象。 如果将图像从一个应用拖到另一个应用,则会拖放二进制数据。 如果我们在 Firefox 中拖动选项卡并将其移动到另一个位置,则将拖放图形组件。

QDrag

QDrag支持基于 MIME 的拖放数据传输。 它处理拖放操作的大多数细节。 传输的数据包含在QMimeData对象中。

简单的拖放

在第一个示例中,我们有一个QLineEdit和一个QPushButton。 我们将纯文本从行编辑小部件中拖放到按钮小部件上。 按钮的标签将更改。

simpledragdrop.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial

This is a simple drag and
drop example. 

Author: Jan Bodnar
Website: zetcode.com
Last edited: August 2017
"""

from PyQt5.QtWidgets import (QPushButton, QWidget, 
    QLineEdit, QApplication)
import sys

class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

        self.setAcceptDrops(True)

    def dragEnterEvent(self, e):

        if e.mimeData().hasFormat('text/plain'):
            e.accept()
        else:
            e.ignore() 

    def dropEvent(self, e):

        self.setText(e.mimeData().text()) 

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        edit = QLineEdit('', self)
        edit.setDragEnabled(True)
        edit.move(30, 65)

        button = Button("Button", self)
        button.move(190, 65)

        self.setWindowTitle('Simple drag and drop')
        self.setGeometry(300, 300, 300, 150)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()  

该示例展示了一个简单的拖动&放下操作。

class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

        ...

为了在QPushButton小部件上放置文本,我们必须重新实现一些方法。 因此,我们创建了自己的Button类,该类将从QPushButton类继承。

self.setAcceptDrops(True)

我们使用setAcceptDrops()为小部件启用放置事件。

def dragEnterEvent(self, e):

    if e.mimeData().hasFormat('text/plain'):
        e.accept()
    else:
        e.ignore() 

首先,我们重新实现dragEnterEvent()方法。 我们告知我们接受的数据类型。 在我们的情况下,它是纯文本。

def dropEvent(self, e):

    self.setText(e.mimeData().text()) 

通过重新实现dropEvent()方法,我们定义了放置事件发生了什么。 在这里,我们更改按钮小部件的文本。

edit = QLineEdit('', self)
edit.setDragEnabled(True)

QLineEdit小部件具有对拖动操作的内置支持。 我们需要做的就是调用setDragEnabled()方法来激活它。

Simple drag and drop

图:简单 drag and drop

拖放按钮小部件

在下面的示例中,我们将演示如何拖放按钮小部件。

dragbutton.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial

In this program, we can press on a button with a left mouse
click or drag and drop the button with  the right mouse click. 

Author: Jan Bodnar
Website: zetcode.com
Last edited: August 2017
"""

from PyQt5.QtWidgets import QPushButton, QWidget, QApplication
from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
import sys

class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

    def mouseMoveEvent(self, e):

        if e.buttons() != Qt.RightButton:
            return

        mimeData = QMimeData()

        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())

        dropAction = drag.exec_(Qt.MoveAction)

    def mousePressEvent(self, e):

        super().mousePressEvent(e)

        if e.button() == Qt.LeftButton:
            print('press')

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        self.setAcceptDrops(True)

        self.button = Button('Button', self)
        self.button.move(100, 65)

        self.setWindowTitle('Click or Move')
        self.setGeometry(300, 300, 280, 150)

    def dragEnterEvent(self, e):

        e.accept()

    def dropEvent(self, e):

        position = e.pos()
        self.button.move(position)

        e.setDropAction(Qt.MoveAction)
        e.accept()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_() 

在我们的代码示例中,窗口上有一个QPushButton。 如果我们用鼠标左键单击该按钮,则会在控制台上显示'press'消息。 通过右键单击并移动按钮,我们可以对按钮小部件执行拖放操作。

class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

我们创建一个从QPushButton派生的Button类。 我们还重新实现了QPushButton的两种方法:mouseMoveEvent()mousePressEvent()mouseMoveEvent()方法是拖放操作开始的地方。

if e.buttons() != Qt.RightButton:
    return

在这里,我们决定只能用鼠标右键执行拖放操作。 鼠标左键保留用于单击该按钮。

mimeData = QMimeData()

drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())

QDrag对象已创建。 该类提供对基于 MIME 的拖放数据传输的支持。

dropAction = drag.exec_(Qt.MoveAction)

拖动对象的exec_()方法开始拖放操作。

def mousePressEvent(self, e):

    super().mousePressEvent(e)

    if e.button() == Qt.LeftButton:
        print('press')

如果我们用鼠标左键单击按钮,我们将在控制台上打印'press'。 注意,我们也在父对象上调用了mousePressEvent()方法。 否则,我们将看不到按钮被按下。

position = e.pos()
self.button.move(position)

dropEvent()方法中,我们指定释放鼠标按钮并完成放置操作后发生的情况。 在本例中,我们找出当前鼠标指针的位置并相应地移动按钮。

e.setDropAction(Qt.MoveAction)
e.accept()

我们用setDropAction()指定放置动作的类型。 在我们的情况下,这是一个动作。

PyQt5 教程的这一部分专门用于拖放操作。

布局管理

原文: http://zetcode.com/gui/csharpqyoto/layoutmanagement/

在 Qyoto C# 编程教程的这一部分中,我们将介绍布局管理器。

在设计应用的 GUI 时,我们决定要使用哪些组件以及如何在应用中组织这些组件。 为了组织我们的组件,我们使用专门的不可见对象,称为布局管理器。 Qyoto 中有多个选项。 我们可以使用绝对定位,内置布局管理器或创建自定义布局管理器。 我们还可以使用 Qt Designer 直观地构建布局。

Qyoto 有一些重要的内置布局管理器。 QVBoxLayout类垂直排列小部件。 QHBoxLayout水平排列小部件。 QGridLayout类将小部件布置在网格中。 网格布局是最灵活的布局管理器。 框布局可以相互嵌套以创建复杂的布局。

绝对定位

在大多数情况下,程序员应使用布局管理器。 在某些情况下,我们可以使用绝对定位。 在绝对定位中,程序员以像素为单位指定每个小部件的位置和大小。 如果调整窗口大小,则窗口小部件的大小和位置不会改变。 应用在各种平台上看起来都不同,在 Linux 上看起来不错,在 Mac 上看起来不好。 在应用中更改字体可能会破坏布局。 如果将应用翻译成另一种语言,则必须重做布局。 对于所有这些问题,仅在有理由时才使用绝对定位。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, we lay out widgets
 * using absolute positioning
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "Absolute";

        InitUI();

        Resize(300, 280);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {        
        StyleSheet = "QWidget { background-color: #414141 }";

        QPixmap bardejov = new QPixmap("bardejov.jpg");
        QPixmap rotunda = new QPixmap("rotunda.jpg");
        QPixmap mincol = new QPixmap("mincol.jpg");

        QLabel barLabel = new QLabel(this);
        barLabel.Pixmap = bardejov;
        barLabel.Move(20, 20);

        QLabel rotLabel = new QLabel(this);
        rotLabel.Pixmap = rotunda;
        rotLabel.Move(40, 160);

        QLabel minLabel = new QLabel(this);
        minLabel.Pixmap = mincol;
        minLabel.Move(170, 50);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在此示例中,我们使用绝对定位显示了三幅图像。

StyleSheet = "QWidget { background-color: #414141 }";

StyleSheet属性用于更改窗口工作区的背景颜色。

QLabel barLabel = new QLabel(this);
barLabel.Pixmap = bardejov;

QLabel小部件用于保存图像。

barLabel.Move(20, 20);

我们使用Move()方法将标签放置在窗口上的x = 20y = 20处。

调整窗口大小时,标签将保留其初始大小。

Absolute

图:绝对定位

按钮示例

在下面的示例中,我们将在窗口的右下角放置两个按钮。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, use box layouts
 * to position two buttons in the
 * bottom right corner of the window.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "Buttons";

        InitUI();

        Resize(300, 150);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {    
        QVBoxLayout vbox = new QVBoxLayout(this);
        QHBoxLayout hbox = new QHBoxLayout();

        QPushButton ok = new QPushButton("OK", this);
        QPushButton apply = new QPushButton("Apply", this);

        hbox.AddWidget(ok, 1, AlignmentFlag.AlignRight);
        hbox.AddWidget(apply);

        vbox.AddStretch(1);
        vbox.AddLayout(hbox);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们使用嵌套框布局来获得我们想要的布局。

QVBoxLayout vbox = new QVBoxLayout(this);
QHBoxLayout hbox = new QHBoxLayout();

我们使用一个垂直框和一个水平框。

QPushButton ok = new QPushButton("OK", this);
QPushButton apply = new QPushButton("Apply", this);

这是两个将进入窗口右下角的按钮。

hbox.AddWidget(ok, 1, AlignmentFlag.AlignRight);

我们将确定按钮放入水平框中。 第二个参数是stretch因子。 它将扩大分配给“确定”按钮的区域。 它会占用所有可用空间。 在此区域内,按钮向右对齐。

vbox.AddStretch(1);

这条线创建了一个垂直扩展的白色空间,它将带有按钮的水平框推到底部。

vbox.AddLayout(hbox);

水平框嵌套在垂直框中。

Buttons example

图:按钮示例

Windows 示例

以下是嵌套框布局更复杂的示例。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, use box layouts
 * to create a windows example.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "Windows";

        InitUI();

        Resize(350, 300);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {
        QVBoxLayout vbox = new QVBoxLayout(this);

        QVBoxLayout vbox1 = new QVBoxLayout();
        QHBoxLayout hbox1 = new QHBoxLayout();
        QHBoxLayout hbox2 = new QHBoxLayout();

        QLabel windLabel = new QLabel("Windows", this);
        QTextEdit edit = new QTextEdit(this);
        edit.Enabled = false;

        QPushButton activate = new QPushButton("Activate", this);
        QPushButton close = new QPushButton("Close", this);
        QPushButton help = new QPushButton("Help", this);
        QPushButton ok = new QPushButton("OK", this);

        vbox.AddWidget(windLabel);

        vbox1.AddWidget(activate);
        vbox1.AddWidget(close, 0, AlignmentFlag.AlignTop);
        hbox1.AddWidget(edit);
        hbox1.AddLayout(vbox1);

        vbox.AddLayout(hbox1);

        hbox2.AddWidget(help);
        hbox2.AddStretch(1);
        hbox2.AddWidget(ok);

        vbox.AddLayout(hbox2, 1);

        Layout = vbox;
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在此布局中,我们使用两个垂直和水平框。

QVBoxLayout vbox = new QVBoxLayout(this);

这是示例的基本布局。

vbox.AddWidget(windLabel);

首先是标签小部件。 它只是转到垂直框的顶部。

vbox1.AddWidget(activate);
vbox1.AddWidget(close, 0, AlignmentFlag.AlignTop);
hbox1.AddWidget(edit);
hbox1.AddLayout(vbox1);

vbox.AddLayout(hbox1);

在窗口的中心部分,我们有一个文本编辑小部件和两个垂直排列的按钮。 这些按钮进入垂直框。 在此垂直框中,按钮与顶部对齐。 垂直框和文本编辑进入水平框。 该水平框转到标签窗口小部件正下方的基本垂直框。

hbox2.AddWidget(help);
hbox2.AddStretch(1);
hbox2.AddWidget(ok);

vbox.AddLayout(hbox2, 1);

帮助和确定按钮进入另一个水平框。 这两个按钮之间有一个扩大的空白区域。 同样,水平框转到基本垂直框。

Layout = vbox;

基本的垂直框设置为窗口的主要布局。

Windows example

图:窗口示例

新文件夹示例

在最后一个示例中,我们使用QGridLayout管理器创建“新文件夹”布局示例。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, use the QGridLayout manager
 * to create a New Folder example.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "New Folder";

        InitUI();

        Resize(300, 300);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {
        QGridLayout grid = new QGridLayout(this);

        QLabel nameLabel = new QLabel("Name", this);
        QLineEdit nameEdit = new QLineEdit(this);
        QTextEdit text = new QTextEdit(this);
        QPushButton okButton = new QPushButton("OK", this);
        QPushButton closeButton = new QPushButton("Close", this);

        grid.AddWidget(nameLabel, 0, 0);
        grid.AddWidget(nameEdit, 0, 1, 1, 3);
        grid.AddWidget(text, 1, 0, 2, 4);
        grid.SetColumnStretch(1, 1);
        grid.AddWidget(okButton, 4, 2);
        grid.AddWidget(closeButton, 4, 3);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在我们的示例中,我们有一个标签,一行编辑,一个文本编辑和两个按钮。

QGridLayout grid = new QGridLayout(this);

我们创建QGridLayout管理器的实例。

grid.AddWidget(nameLabel, 0, 0);

我们将标签小部件放置在网格的第一个单元格中。 单元格从 0 开始计数。最后两个参数是行号和列号。

grid.AddWidget(nameEdit, 0, 1, 1, 3);

线编辑窗口小部件位于第一行第二列。 最后两个参数是行跨度和列跨度。 在水平方向上,小部件将跨越三列。

grid.SetColumnStretch(1, 1);

该方法的参数是列号和拉伸因子。 在这里,我们将拉伸因子 1 设置到第二列。 这意味着此列将占用所有剩余空间。 之所以这样设置,是因为我们希望按钮保持其初始大小。

New Folder example

图:新文件夹 example

在 Qyoto C# 教程的这一部分中,我们提到了小部件的布局管理。

{% raw %}

Qyoto 中的小部件

原文: http://zetcode.com/gui/csharpqyoto/widgets/

在 Qyoto C# 编程教程的这一部分中,我们将介绍 Qyoto 小部件。

小部件是 GUI 应用的基本构建块。 多年来,几个小部件已成为所有 OS 平台上所有工具包中的标准。 例如,按钮,复选框或滚动条。 Qyoto 有一组丰富的小部件,可以满足大多数编程需求。 可以将更多专门的窗口小部件创建为自定义窗口小部件。

QCheckBox

QCheckBox是具有两种状态的窗口小部件:开和关。 接通状态通过复选标记显示。 它用来表示一些布尔属性。 QCheckBox小部件提供一个带有文本标签的复选框。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program uses QCheckBox
 * widget to show/hide the title
 * of the window.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "QCheckBox";

        SetupUI();

        Resize(250, 150);
        Move(300, 300);
        Show();
    }    

    public void SetupUI() 
    {       
        QCheckBox cb = new QCheckBox("Show Title", this);
        cb.Checked = true;
        cb.Move(50, 50);

        cb.StateChanged += ShowTitle;
    }

    [Q_SLOT]
    public void ShowTitle(int state) 
    {
        if (state == (int) CheckState.Checked) 
        {
            WindowTitle = "QCheckBox";
        } else {
            WindowTitle = "";
        }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在我们的示例中,我们在窗口上放置了一个复选框。 复选框显示/隐藏窗口的标题。

WindowTitle = "QCheckBox";

在构建窗口期间,我们为窗口设置标题。

QCheckBox cb = new QCheckBox("Show Title", this);

QCheckBox小部件已创建。 构造器的第一个参数是其文本标签。 第二个参数是父窗口小部件。

cb.Checked = true;

标题在应用的开始处可见。 因此,也必须选中该复选框。 我们通过Checked属性选中该复选框。

cb.StateChanged += ShowTitle;

我们将ShowTitle()方法插入StateChange事件。 复选框的状态更改时,将发出事件。

[Q_SLOT]
public void ShowTitle(int state) 
{
   ...
}

方法定义之前带有Q_SLOT属性。 此属性通知编译器有关自定义槽的信息。

if (state == (int) CheckState.Checked) 
{
    WindowTitle = "QCheckBox";
} else {
    WindowTitle = "";
}

根据复选框的状态,我们显示或隐藏窗口的标题。

QCheckBox

图:QCheckBox

QLabel

QLabel小部件用于显示文本或图像。 没有用户交互。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program uses QLabel to 
 * show lyrics of a song.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "You know I'm no Good";

        InitUI();

        Resize(250, 150);
        Move(300, 300);
        Show();
    }

    public void InitUI() 
    {
           string text = @"Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
You say why did you do it with him today?
and sniff me out like I was Tanqueray

cause you're my fella, my guy
hand me your stella and fly
by the time I'm out the door
you tear men down like Roger Moore

I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good";

        QLabel label = new QLabel(text, this);
        label.Font = new QFont("Purisa", 9);

        QVBoxLayout vbox = new QVBoxLayout();
        vbox.AddWidget(label);
        Layout = vbox;
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们的示例在窗口中显示了歌曲的歌词。

string text = @"Meet you downstairs in the bar and heard
...

我们定义了多行文字。 多行文本在 C# 语言中以@字符开头。

QLabel label = new QLabel(text, this);
label.Font = new QFont("Purisa", 9);

我们创建标签小部件并更改其字体。

QVBoxLayout vbox = new QVBoxLayout();
vbox.AddWidget(label);
Layout = vbox;

代替手动编码标签的位置和大小,我们将标签放入盒子布局中。

QLabel

图:QLabel

QLineEdit

QLineEdit是一个小部件,允许输入和编辑单行纯文本。 QLineEdit小部件具有撤消/重做,剪切/粘贴和拖放功能。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program shows text
 * which is entered in a QLineEdit
 * widget in a QLabel widget.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    QLabel label;

    public QyotoApp() 
    {
        WindowTitle = "QLineEdit";

        InitUI();

        Resize(250, 150);
        Move(400, 300);
        Show();
    }    

    public void InitUI() 
    {        
        label = new QLabel(this);

        QLineEdit edit = new QLineEdit(this);
        edit.TextChanged += OnChanged;

        edit.Move(60, 100);
        label.Move(60, 40);
    }

    [Q_SLOT]
    public void OnChanged(string text) 
    {
        label.Text = text;
        label.AdjustSize();
    }

    [STAThread]
    public static int Main(string[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在我们的示例中,我们显示了两个小部件。 行编辑和标签小部件。 输入到行编辑中的文本显示在标签窗口小部件中。

QLineEdit edit = new QLineEdit(this);

QLineEdit小部件已创建。

edit.TextChanged += OnChanged;

当我们在行编辑中键入或删除某些文本时,将触发OnChanged()方法。 该方法采用字符串参数。

[Q_SLOT]
public void OnChanged(string text) 
{
    label.Text = text;
    label.AdjustSize();
}

OnChanged()方法中,我们将行编辑的内容设置为标签窗口小部件。 AdjustSize()方法确保所有文本都是可见的。

QLineEdit widget

图:QLineEdit小部件

ToggleButton

切换按钮是设置了可检查标志的按钮。 切换按钮是具有两种状态的按钮。 已按下但未按下。 通过单击可以在这两种状态之间切换。 在某些情况下此功能非常合适。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program uses toggle buttons to
 * change the background colour of
 * a widget.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    QWidget square;
    QColor col;

    QPushButton redb;
    QPushButton greenb;
    QPushButton blueb;

    public QyotoApp() 
    {
        WindowTitle = "Toggle buttons";

        InitUI();

        Resize(350, 240);
        Move(400, 300);
        Show();
    }

    private void InitUI() 
    {
        col = new QColor();

        redb = new QPushButton("Red", this);
        redb.Checkable = true;
        greenb = new QPushButton("Green", this);
        greenb.Checkable = true;
        blueb = new QPushButton("Blue", this);
        blueb.Checkable = true;

        redb.Toggled += OnToggled;
        greenb.Toggled += OnToggled;
        blueb.Toggled += OnToggled;

        square = new QWidget(this);
        square.StyleSheet = "QWidget { background-color: black }";

        redb.Move(30, 30);
        greenb.Move(30, 80);
        blueb.Move(30, 130);
        square.SetGeometry(150, 25, 150, 150);
    }

    [Q_SLOT]
    public void OnToggled(bool @checked) 
    {
        int red = col.Red;
        int green = col.Green;
        int blue = col.Blue;

        if (redb.Checked) 
        {
            red = 255;
        } else {
            red = 0;
        }

        if (greenb.Checked) 
        {
            green = 255;
        } else {
            green = 0;
        }

        if (blueb.Checked) 
        {
            blue = 255;
        } else {
            blue = 0;
        }

        col = new QColor(red, green, blue);

        string sheet = System.String.Format("QWidget {{ background-color: {0} }}", 
            col.Name());
        square.StyleSheet = sheet;
    }

    [STAThread]    
    public static int Main(string[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在代码示例中,我们使用三个切换按钮来更改矩形小部件的颜色。

QWidget square;
QColor color;

QPushButton redb;
QPushButton greenb;
QPushButton blueb;

我们定义了五个对象。 方形小部件是QWidget,它显示颜色。 color变量用于保存颜色值。 这三个按钮是切换按钮,用于混合颜色值。

redb = new QPushButton("Red", this);
redb.Checkable = true;

我们创建一个QPushButton小部件。 Checkable属性将按钮更改为切换按钮。

redb.Toggled += OnToggled;
greenb.Toggled += OnToggled;
blueb.Toggled += OnToggled;

所有三个按钮都插入到一个方法调用中,即OnToggled()方法。

square = new QWidget(this);
square.StyleSheet = "QWidget { background-color: black }";

我们创建方形小部件。 一开始是黑色的。 在 Qyoto 中,我们使用样式表来自定义小部件的外观。

OnToggled()方法内部,我们确定颜色值并将正方形小部件更新为新颜色。

int red = col.Red;
int green = col.Green;
int blue = col.Blue;

在这里,我们确定方形小部件的当前颜色。

if (redb.Checked) 
{
    red = 255;
} else {
    red = 0;
}

根据红色切换按钮的状态,更改颜色的红色部分。

col = new QColor(red, green, blue);

我们创建一个新的颜色值。

string sheet = System.String.Format("QWidget {{ background-color: {0} }}", 
    col.Name());        

我们使用 C# Format方法创建适当的样式表。

square.StyleSheet = sheet;

正方形的颜色已更新。

Toggle buttons

图:开关按钮

QComboBox

QComboBox是一个小部件,允许用户从选项列表中进行选择。 这是一个显示当前项目的选择小部件,可以弹出可选择项目的列表。 组合框可能是可编辑的。 它以占用最少屏幕空间的方式向用户显示选项列表。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program uses the QComboBox widget.
 * The option selected from the combo box is
 * displayed in the label widget.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{    
    QLabel label;

    public QyotoApp() 
    {
        WindowTitle = "QComboBox";

        InitUI();

        Resize(250, 150);
        Move(300, 300);
        Show();
    }

    public void InitUI() 
    {       
        label = new QLabel("Ubuntu", this);

        QComboBox combo = new QComboBox(this);
        combo.AddItem("Ubuntu");
        combo.AddItem("Arch");
        combo.AddItem("Fedora");
        combo.AddItem("Red Hat");
        combo.AddItem("Gentoo");

        combo.Move(50, 30);
        label.Move(50, 100);

        combo.ActivatedString += OnActivated;
    }

    [Q_SLOT]
    public void OnActivated(string text) 
    {
        label.Text = text;
        label.AdjustSize();
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在我们的代码示例中,我们有两个小部件。 组合框和标签小部件。 从组合框中选择的选项显示在标签中。

label = new QLabel("Ubuntu", this);

这是一个标签,它将显示组合框中当前选择的选项。

QComboBox combo = new QComboBox(this);

我们创建QComboBox小部件的实例。

combo.AddItem("Ubuntu");
combo.AddItem("Arch");
combo.AddItem("Fedora");
combo.AddItem("Red Hat");
combo.AddItem("Gentoo");

组合框将填充值。

combo.ActivatedString += OnActivated;

当我们从组合框中选择一个选项时,将触发OnActivated()方法。

[Q_SLOT]
public void OnActivated(string text) 
{
    label.Text = text;
    label.AdjustSize();
}

OnActivated()方法中,我们将标签小部件更新为从组合框中选择的当前字符串。

QComboBox widget

图:QComboBox小部件

在 Qyoto C# 教程的这一部分中,我们介绍了几个 Qyoto 小部件。

{% endraw %}

Qyoto 中的菜单和工具栏

原文: http://zetcode.com/gui/csharpqyoto/menustoolbars/

在 Qyoto C# 编程教程的这一部分中,我们将使用菜单和工具栏。

菜单栏是 GUI 应用中最可见的部分之一。 它是位于各个菜单中的一组命令。 菜单将我们可以在应用中使用的命令分组。 使用工具栏可以快速访问最常用的命令。

简单菜单

第一个示例将显示一个简单的菜单。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program shows a simple
 * menu. It has one action, which
 * will terminate the program, when
 * selected. 
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Simple menu";

        InitUI();

        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void InitUI() 
    {
        QAction quit = new QAction("&Quit", this);

        QMenu file = MenuBar.AddMenu("&File");
        file.AddAction(quit);

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们有一个菜单栏,一个菜单和一个动作。 为了使用菜单,我们必须继承QMainWindow小部件。

QAction quit = new QAction("&Quit", this);

此代码行创建一个QAction。 每个QMenu具有一个或多个动作对象。 注意 AND 字符(&)。 它为以下项目创建快捷方式: Alt + Q 。 它还强调了Q字符。 下拉文件菜单时,该快捷方式处于活动状态。

QMenu file = MenuBar.AddMenu("&File");
file.AddAction(quit);

我们创建一个QMenu对象。 &字符创建快捷方式: Alt + F 。 连续的快捷方式 Alt + FAlt + Q 终止应用。

Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));

当我们从菜单中选择此选项时,应用终止。

Simple menu

图:简单菜单

创建一个子菜单

子菜单是插入另一个菜单对象的菜单。 下一个示例对此进行了演示。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program creates a
 * submenu.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Submenu";

        InitUI();

        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void InitUI() 
    {
        QAction quit = new QAction("&Quit", this);

        QMenu file = MenuBar.AddMenu("&File");
        QMenu impm = new QMenu("Import");

        QAction seeds = new QAction("Import news feed...", this);
        QAction marks = new QAction("Import bookmarks...", this);
        QAction mail = new QAction("Import mail...", this);

        impm.AddAction(seeds);
        impm.AddAction(marks);
        impm.AddAction(mail);

        file.AddMenu(impm);
        file.AddAction(quit);

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在示例中,文件菜单的子菜单中有三个选项。

QMenu file = MenuBar.AddMenu("&File");
QMenu impm = new QMenu("Import");

我们有两个QMenu对象。 文件菜单和导入菜单。

QAction seeds = new QAction("Import news feed...", this);
QAction marks = new QAction("Import bookmarks...", this);
QAction mail = new QAction("Import mail...", this);

我们创建三个动作对象。

impm.AddAction(seeds);
impm.AddAction(marks);
impm.AddAction(mail);

我们将动作对象添加到导入菜单中。

file.AddMenu(impm);

最后,我们将导入菜单添加到文件菜单中。

Submenu

图:子菜单

图像,菜单,分隔符

在以下示例中,我们将进一步增强以前的应用。 我们将在菜单中添加图标,使用快捷方式和分隔符。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program shows image menu items, a shorcut
 * and a separator.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Image menu";

        InitUI();

        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void InitUI() 
    {
        QIcon newpix = new QIcon("new.png");
        QIcon openpix = new QIcon("open.png");
        QIcon quitpix = new QIcon("quit.png");

        QAction newa = new QAction(newpix, "&New", this);
        QAction open = new QAction(openpix, "&Open", this);
        QAction quit = new QAction(quitpix, "&Quit", this);
        quit.Shortcut = "CTRL+Q";

        QMenu file;
        file = MenuBar.AddMenu("&File");
        file.AddAction(newa);
        file.AddAction(open);
        file.AddSeparator();
        file.AddAction(quit);

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在我们的示例中,我们有一个包含三个动作的菜单。 如果我们选择退出操作,则实际上只有退出操作才可以执行某些操作。 我们还创建了一个分隔符和Ctrl + Q快捷键,它们将终止应用。

QIcon newpix = new QIcon("new.png");
QIcon openpix = new QIcon("open.png");
QIcon quitpix = new QIcon("quit.png");

这些是我们将在应用中使用的 PNG 图像。

QAction newa = new QAction(newpix, "&New", this);
QAction open = new QAction(openpix, "&Open", this);
QAction quit = new QAction(quitpix, "&Quit", this);

在这里,我们创建三个动作对象。 第一个参数是QIcon

quit.Shortcut = "CTRL+Q";

这行创建一个快捷方式。 通过按下此快捷方式,我们将运行退出操作,这将退出应用。

file.AddSeparator();

我们创建一个分隔符。 分隔符是一条水平线,它使我们能够将菜单操作分组为一些逻辑部分。

Images, shortcut and a separator

图:图像 s, shortcut and a separator

工具栏

QToolBar类提供了一个可移动面板,其中包含一组控件,这些控件提供对应用操作的快速访问。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program creates a 
 * toolbar.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Toolbar";

        InitUI();

        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void InitUI() 
    {
        QIcon newpi = new QIcon("new.png");
        QIcon openpi = new QIcon("open.png");
        QIcon quitpi = new QIcon("quit.png");

        QToolBar toolbar = AddToolBar("main toolbar");
        toolbar.AddAction(newpi, "New File");
        toolbar.AddAction(openpi, "Open File");
        toolbar.AddSeparator();
        QAction quit = toolbar.AddAction(quitpi,
            "Quit Application");

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们创建一个带有三个动作对象和一个分隔符的工具栏。

QIcon newpi = new QIcon("new.png");
QIcon openpi = new QIcon("open.png");
QIcon quitpi = new QIcon("quit.png");

工具栏动作对象将显示这些图标。

QToolBar toolbar = AddToolBar("main toolbar");

QMainWindow类的AddToolBar()方法为应用创建一个工具栏。 文本字符串为工具栏命名。 此名称用于引用此工具栏,因为一个应用中可以有多个工具栏。 如果右键单击窗口区域,我们将看到一个可检查的选项,该选项显示/隐藏工具栏。

toolbar.AddSeparator();

我们创建一个垂直分隔符。

Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));

当我们单击退出操作对象时,应用终止。

Toolbar

图:工具栏

撤销重做

以下示例演示了如何停用工具栏上的工具栏按钮。 这是 GUI 编程中的常见做法。 例如,保存按钮。 如果我们将文档的所有更改都保存到磁盘上,则在大多数文本编辑器中,“保存”按钮将被停用。 这样,应用会向用户指示所有更改都已保存。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program disables/enables
 * toolbuttons on a toolbar.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QMainWindow 
{    
    int count = 0;
    QToolButton undoButton;
    QToolButton redoButton;

    public QyotoApp() 
    {
        WindowTitle = "Undo redo";

        InitUI();

        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void InitUI() 
    {
        QIcon undoi = new QIcon("undo.png");
        QIcon redoi = new QIcon("redo.png");
        QIcon quitpi = new QIcon("quit.png");

        QToolBar toolbar = new QToolBar();
        undoButton = new QToolButton();
        redoButton = new QToolButton();

        QAction undoAction = new QAction(undoi, "Undo", undoButton);
        QAction redoAction = new QAction(redoi, "Redo", redoButton);

        undoButton.DefaultAction = undoAction;
        redoButton.DefaultAction = redoAction;

        toolbar.AddWidget(undoButton);
        toolbar.AddWidget(redoButton);
        toolbar.AddSeparator();

        QAction quit = toolbar.AddAction(quitpi, "Quit Application");

        undoButton.Triggered += Count;
        redoButton.Triggered += Count;

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));

        AddToolBar(toolbar);        
    }

    [Q_SLOT]
    void Count(QAction action) 
    {
        if ("Undo".Equals(action.Text)) 
        {
            count += -1;
        } 
        else 
        {
            count += 1;
        }

        if (count <= 0) 
        {
            undoButton.SetDisabled(true);
            redoButton.SetDisabled(false);
        }

        if (count >= 5) 
        {
            undoButton.SetDisabled(false);
            redoButton.SetDisabled(true);
        }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在我们的示例中,我们有三个QAction对象和一个分隔符。 在撤消或重做按钮上单击几下后,它们将被停用。 外观上,按钮显示为灰色。

int count = 0;

计数变量确定哪个按钮被激活和停用。

undoButton.Triggered += Count;
redoButton.Triggered += Count;

单击工具栏按钮,将发射Triggered信号。 我们将此信号连接到Count()方法。 它接收触发它的QAction对象。

if ("Undo".Equals(action.Text)) 
{
    count += -1;
} 
else 
{
    count += 1;
}

撤消工具栏按钮从计数变量中减去 1。 重做添加 1.根据计数变量的值,我们启用/禁用工具栏按钮。

if (count <= 0) 
{
    undoButton.SetDisabled(true);
    redoButton.SetDisabled(false);
}

SetDisabled()方法激活或停用工具栏按钮。

Undo redo

图:撤销和重做

在 Qyoto C# 教程的这一部分中,我们提到了菜单和工具栏。

{% raw %}

Qyoto 对话框

原文: http://zetcode.com/gui/csharpqyoto/dialogs/

在 Qyoto C# 编程教程的这一部分中,我们将使用对话框。

对话框窗口或对话框是大多数现代 GUI 应用必不可少的部分。 对话被定义为两个或更多人之间的对话。 在计算机应用中,对话框是一个窗口,用于与应用“对话”。 对话框用于输入数据,修改数据,更改应用设置等。对话框是用户与计算机程序之间进行通信的重要手段。

MessageDialog

消息框是方便的对话框,可向应用的用户提供消息。 该消息由文本和图像数据组成。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program shows
 * QMessageBox dialogs
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    public QyotoApp() 
    {
        WindowTitle = "Message boxes";

        InitUI();

        Resize(220, 90);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {        
        QGridLayout grid = new QGridLayout(this);
        grid.Spacing = 2;

        QPushButton error = new QPushButton("Error", this);
        QPushButton warni = new QPushButton("Warning", this);
        QPushButton quest = new QPushButton("Question", this);
        QPushButton infor = new QPushButton("Information", this);
        QPushButton about = new QPushButton("About", this);

        grid.AddWidget(error, 0, 0);
        grid.AddWidget(warni, 0, 1);
        grid.AddWidget(quest, 1, 0);
        grid.AddWidget(infor, 1, 1);
        grid.AddWidget(about, 2, 0);

        error.Clicked += ShowDialog;
        warni.Clicked += ShowDialog;
        quest.Clicked += ShowDialog;
        infor.Clicked += ShowDialog;
        about.Clicked += ShowDialog;                
    }

    [Q_SLOT]
    void ShowDialog() 
    {
        QPushButton btn = (QPushButton) Sender();

        if ("Error".Equals(btn.Text)) 
        {
            QMessageBox.Critical(this, "Error", "Error loading file!");
        } else if ("Warning".Equals(btn.Text)) 
        {
            QMessageBox.Warning(this, "Warning", "Operation not permitted!");
        } else if ("Question".Equals(btn.Text)) 
        {
            QMessageBox.Question(this, "Question", "Are you sure to quit?");
        } else if ("Information".Equals(btn.Text)) 
        {
            QMessageBox.Information(this, "Information", "Download completed.");
        } else if ("About".Equals(btn.Text)) 
        {
            QMessageBox.About(this, "About", "ZetCode Qyoto C# tutorial.");
        } 
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们使用GridLayout管理器来设置五个按钮的网格。 每个按钮显示一个不同的消息框。

QPushButton button = (QPushButton) Sender();

在这里,我们确定哪个按钮称为ShowDialog()方法。

if ("Error".Equals(btn.Text)) 
{
    QMessageBox.Critical(this, "Error", "Error loading file!");
} 

如果按下错误按钮,则会显示错误对话框。 我们使用QMessageBox类的静态方法来显示消息框。

Information message dialog

Warning message dialog

Question message dialog

Error message dialog

About message dialog

QInputDialog

QInputDialog类提供了一个简单的便捷对话框,可从用户那里获取单个值。 输入值可以是字符串,数字或列表中的。 必须设置标签以告知用户他们应该输入什么。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program shows an input
 * dialog.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    QLineEdit edit;

    public QyotoApp() 
    {
        WindowTitle = "QInputDialog";

        InitUI();

        Resize(300, 150);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {        
        QPushButton show = new QPushButton("Dialog", this);
        show.Clicked += ShowDialog;

        show.FocusPolicy = Qt.FocusPolicy.NoFocus;
        show.Move(20, 20);

        edit = new QLineEdit(this);
        edit.Move(130, 22);
    }

    [Q_SLOT]
    void ShowDialog() 
    {        
        String text = QInputDialog.GetText(
                this, "Input Dialog", "Enter your name");

        if (text!=null && text.Trim() != String.Empty) 
        {
            edit.Text = text;
        }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在代码示例中,我们有一个按钮和一行编辑。 该按钮显示一个输入对话框。 我们得到一些文本,文本显示在行编辑小部件中。

String text = QInputDialog.GetText(
        this, "Input Dialog", "Enter your name");

GetText()静态方法创建输入对话框。 对话框中的文本存储在text变量中。

if (text!=null && text.Trim() != String.Empty) 
{
    edit.Text = text;
}

在更新行编辑之前,请确保text变量不为null且不为空,并且不仅由空格组成。

Input dialog

图:输入对话框

QColorDialog

QColorDialog类提供用于指定颜色的对话框小部件。 颜色对话框的功能是允许用户选择颜色。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, we use the
 * QColorDialog to change the colour
 * of a label text.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    QLabel label;

    public QyotoApp() : base() 
    {
        WindowTitle = "QColorDialog";

        InitUI();

        Resize(250, 200);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {
        label = new QLabel("ZetCode Qyoto C# tutorial", this);

        QVBoxLayout vbox = new QVBoxLayout(this);
        label.Alignment = AlignmentFlag.AlignCenter;
        vbox.AddWidget(label);
    }    

    protected override void OnMousePressEvent(QMouseEvent arg1) 
    {
        QColor col = QColorDialog.GetColor();

        if (!col.IsValid()) return;

        String style = String.Format("QWidget {{ color: {0} }}", col.Name());
        label.StyleSheet = style;
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们在窗口中心显示一些文本。 通过单击窗口区域,我们显示一个颜色对话框。 我们将文本前景色更改为从对话框中选择的颜色。

protected override void OnMousePressEvent(QMouseEvent arg1) 
{
    ...
}

为了接收我们窗口的鼠标按下事件,我们必须重写MousePressEvent()方法。

QColor col = QColorDialog.GetColor();

正在创建QColorDialog。 所选颜色存储在col变量中。

if (!color.IsValid()) return;

当按下取消按钮时,我们什么也不做。

String style = String.Format("QWidget {{ color: {0} }}", color.Name());
label.SetStyleSheet(style);

在这里,我们更新标签文本的前景色。

QColorDialog

图:QColorDialog

QFontDialog

QFontDialog类提供用于选择字体的对话框小部件。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, we use the
 * QFontDialog to change the font
 * of a label text.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{    
    QLabel label;

    public QyotoApp() : base() 
    {
        WindowTitle = "QFontDialog";

        InitUI();

        Resize(250, 200);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {
        label = new QLabel("ZetCode Qyoto C# tutorial", this);

        QVBoxLayout vbox = new QVBoxLayout(this);
        label.Alignment = AlignmentFlag.AlignCenter;
        vbox.AddWidget(label);
    }

    protected override void OnMousePressEvent(QMouseEvent arg1) 
    {
        bool ok = true;
        QFont font = QFontDialog.GetFont(ref ok);
        if (!ok) return;
        label.Font = font;
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

此示例与上一个示例相似。 这次,我们更改文本的字体。

QFont font = QFontDialog.GetFont(ref ok);

正在创建QFontDialog。 当我们按下对话框的 OK 按钮时,将设置boolean ok变量。

if (!ok) return;

如果不按“确定”按钮,我们什么也不做。

label.Font = font;

font字段存储所选字体。 我们将标签的字体更新为新选择的字体。

QFontDialog

图:QFontDialog

在 Qyoto C# 教程的这一部分中,我们使用了对话框窗口。

{% endraw %}

Qyoto 中的绘图

原文: http://zetcode.com/gui/csharpqyoto/painting/

在 Qyoto C# 编程教程的这一部分中,我们将进行绘图。

当我们在京都进行绘图时,QPainter类非常有用。 绘图事件通过OnPaintEvent()方法接收。 若要进行自定义绘图,我们必须重新实现此方法。

图案

在《京都议定书》中,我们可以使用各种图案来填充形状的内部。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws nine rectangles.
 * The interiors are filled with
 * different built-in patterns.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{
    public QyotoApp() 
    {
        WindowTitle = "Patterns";

        PaintEvent += OnPaintEvent;

        Resize(350, 280);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {
        QPainter ptr = new QPainter(this);
        DrawPatterns(ptr);

        ptr.End();
    }

    void DrawPatterns(QPainter ptr) 
    {
        ptr.SetPen(Qt.PenStyle.NoPen);

        ptr.SetBrush(Qt.BrushStyle.HorPattern);
        ptr.DrawRect(10, 15, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.VerPattern);
        ptr.DrawRect(130, 15, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.CrossPattern);
        ptr.DrawRect(250, 15, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.Dense7Pattern);
        ptr.DrawRect(10, 105, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.Dense6Pattern);
        ptr.DrawRect(130, 105, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.Dense5Pattern);
        ptr.DrawRect(250, 105, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.BDiagPattern);
        ptr.DrawRect(10, 195, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.FDiagPattern);
        ptr.DrawRect(130, 195, 90, 60);

        ptr.SetBrush(Qt.BrushStyle.DiagCrossPattern);
        ptr.DrawRect(250, 195, 90, 60);
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在代码示例中,我们将绘制九个矩形,并用不同的画笔图案填充它们。

PaintEvent += OnPaintEvent;

在绘制事件中执行绘制。 我们将OnPaintEvent()方法插入到绘画事件。

private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
{
    QPainter ptr = new QPainter(this);
    DrawPatterns(ptr);

    ptr.End();
}

当需要重绘窗口区域时,将调用OnPaintEvent()方法。 当我们调整窗口大小,最大化或最小化窗口时,就会发生这种情况。在此方法中,我们创建了QPainter对象。 该对象用于完成 Qyoto 中的所有绘图。 绘图本身被委托给DrawPatterns()方法。 End()方法释放绘图时使用的资源。

ptr.SetPen(Qt.PenStyle.NoPen);

笔对象用于绘制形状的轮廓。 在我们的示例中,我们将不使用笔。

ptr.SetBrush(Qt.BrushStyle.HorPattern);

我们将水平图案设置为画笔。

ptr.DrawRect(10, 15, 90, 60);

我们使用当前的笔和画笔绘制一个矩形。 该方法的前两个参数是 x,y 坐标。 最后两个参数是矩形的宽度和高度。

Patterns

图:图案

形状

Qyoto 绘图 API 可以绘制各种形状。 以下编程代码示例将显示其中的一些。

using System;
using System.Collections.Generic;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws basic shapes
 * available in Qyoto.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Shapes";

        PaintEvent += OnPaintEvent;

        Resize(350, 280);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {
        QPainter ptr = new QPainter(this);
        DrawShapes(ptr);

        ptr.End();
    }

    void DrawShapes(QPainter ptr) 
    {
        ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);
        ptr.Pen = new QPen(new QBrush(new QColor("Gray")), 1);
        ptr.Brush = new QColor("Gray");

        QPainterPath path1 = new QPainterPath();

        path1.MoveTo(5, 5);
        path1.CubicTo(40, 5,  50, 50,  99, 99);
        path1.CubicTo(5, 99,  50, 50,  5, 5);
        ptr.DrawPath(path1);

        ptr.DrawPie(130, 20, 90, 60, 30*16, 120*16);
        ptr.DrawChord(240, 30, 90, 60, 0, 16*180);
        ptr.DrawRoundRect(20, 120, 80, 50);

        List<QPoint> points = new List<QPoint>();
        points.Add(new QPoint(130, 140));
        points.Add(new QPoint(180, 170));
        points.Add(new QPoint(180, 140));
        points.Add(new QPoint(220, 110));
        points.Add(new QPoint(140, 100));

        QPolygon polygon = new QPolygon(points);
        ptr.DrawPolygon(polygon);

        ptr.DrawRect(250, 110, 60, 60);

        QPointF baseline = new QPointF(20, 250);
        QFont font = new QFont("Georgia", 55);
        QPainterPath path2 = new QPainterPath();
        path2.AddText(baseline, font, "Q");
        ptr.DrawPath(path2);

        ptr.DrawEllipse(140, 200, 60, 60);
        ptr.DrawEllipse(240, 200, 90, 60);
    }

    [STAThread]    
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在此代码示例中,我们在窗口上绘制了九种不同的形状。 复杂路径,饼图,和弦,圆角矩形,多边形,矩形,基于字符的形状,圆形和椭圆形。

ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);

我们在示例中使用抗锯齿。 抗锯齿形状看起来更好,但是绘制它们需要更多时间。

ptr.Pen = new QPen(new QBrush(new QColor("Gray")), 1);
ptr.Brush = new QColor("Gray");

我们使用深灰色的笔和画笔绘制形状。

QPainterPath path1 = new QPainterPath();

path1.MoveTo(5, 5);
path1.CubicTo(40, 5,  50, 50,  99, 99);
path1.CubicTo(5, 99,  50, 50,  5, 5);
ptr.DrawPath(path1);

使用QPainterPath对象创建第一个复杂形状。 QPainterPath类为绘图操作提供了一个容器。 画家路径是由许多图形构造块(例如矩形,椭圆形,直线和曲线)组成的对象。

ptr.DrawPie(130, 20, 90, 60, 30*16, 120*16);
ptr.DrawChord(240, 30, 90, 60, 0, 16*180);
ptr.DrawRoundRect(20, 120, 80, 50);

这三行画出一个饼图,一个和弦和一个圆角矩形。

List<QPoint> points = new List<QPoint>();
points.Add(new QPoint(130, 140));
points.Add(new QPoint(180, 170));
points.Add(new QPoint(180, 140));
points.Add(new QPoint(220, 110));
points.Add(new QPoint(140, 100));

QPolygon polygon = new QPolygon(points);
ptr.DrawPolygon(polygon);

我们使用五个点的列表来创建多边形。

QPointF baseline = new QPointF(20, 250);
QFont font = new QFont("Georgia", 55);
QPainterPath path2 = new QPainterPath();
path2.AddText(baseline, font, "Q");
ptr.DrawPath(path2);

这些线创建基于字符的形状。

ptr.DrawEllipse(140, 200, 60, 60);
ptr.DrawEllipse(240, 200, 90, 60);

这两条线分别创建一个圆和一个椭圆。

Shapes

图:形状

透明矩形

透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。

在计算机图形学中,我们可以使用 alpha 合成来实现透明效果。 Alpha 合成是将图像与背景组合以创建部分透明外观的过程。 合成过程使用 Alpha 通道。 (wikipedia.org,answers.com)

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws ten rectangles with 
 * different levels of transparency.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Transparent rectangles";

        PaintEvent += OnPaintEvent;

        Resize(590, 90);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {  
        QPainter ptr = new QPainter(this);
        DrawRectangles(ptr);

        ptr.End();
    }

    void DrawRectangles(QPainter ptr) 
    {
        ptr.SetPen(Qt.PenStyle.NoPen);

        for (int i=1; i<11; i++) 
        {
            ptr.Brush = new QColor(0, 0, 255, i*25);
            ptr.DrawRect(50*i, 20, 40, 40);
        }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在示例中,我们将绘制十个具有不同透明度级别的矩形。

ptr.SetPen(Qt.PenStyle.NoPen);

我们不用笔。

for (int i=1; i<11; i++) 
{
    ptr.Brush = new QColor(0, 0, 255, i*25);
    ptr.DrawRect(50*i, 20, 40, 40);
}

QColor对象的最后一个参数是 alpha 透明度值。

Transparent rectangles

图:透明矩形

绘制文字

在最后一个示例中,我们将在窗口上绘制文本。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws text
 * on the window.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Soulmate";

        PaintEvent += OnPaintEvent;

        Resize(370, 240);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    { 
        QPainter ptr = new QPainter(this);
        DrawLyrics(ptr);

        ptr.End();
    }

    void DrawLyrics(QPainter ptr) 
    {
        ptr.Brush = new QColor(25, 25, 25);
        ptr.Font = new QFont("Courier", 10);

        ptr.DrawText(new QPoint(20, 30),
                "Most relationships seem so transitory");
        ptr.DrawText(new QPoint(20, 60),
                "They're good but not the permanent one");
        ptr.DrawText(new QPoint(20, 120),
                "Who doesn't long for someone to hold");
        ptr.DrawText(new QPoint(20, 150),
                "Who knows how to love without being told");
        ptr.DrawText(new QPoint(20, 180),
                "Somebody tell me why I'm on my own");
        ptr.DrawText(new QPoint(20, 210),
                "If there's a soulmate for everyone");
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们在窗口上画一首歌歌词。

ptr.Font = new QFont("Courier", 10);

我们为文本设置了 Courier 字体。

ptr.DrawText(new QPoint(20, 30),
        "Most relationships seem so transitory");

DrawText()方法用于在x = 20y = 30处绘制文本。

Drawing text

图:绘制文本

在 Qyoto C# 编程教程的这一部分中,我们做了一些绘图。

Qyoto 中的绘图 II

原文: http://zetcode.com/gui/csharpqyoto/paintingII/

在 Qyoto C# 编程教程的这一部分中,我们将继续绘图。 我们将提供一些更复杂的示例。

甜甜圈形状

第一个示例通过旋转一堆椭圆来创建复杂的形状。

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws a donut
 * shape.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Donut";

        PaintEvent += OnPaintEvent;

        Resize(350, 280);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {
        QPainter ptr = new QPainter(this);
        DrawDonut(ptr);

        ptr.End();
     }

    void DrawDonut(QPainter ptr) 
    {
        QColor col = new QColor();
        col.SetNamedColor("#333333");

        ptr.Pen = new QPen(col, 0.5);

        ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);

        int h = Height;
        int w = Width;

        ptr.Translate(new QPoint(w/2, h/2));

         for (double rot=0; rot < 360.0; rot+=5.0 ) 
         {
             ptr.DrawEllipse(-125, -40, 250, 80);
             ptr.Rotate(5.0);
         }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

在此示例中,我们创建一个甜甜圈。 形状类似于曲奇,因此得名“甜甜圈”。

QColor color = new QColor();
color.SetNamedColor("#333333");

我们可以使用十六进制表示法来创建颜色对象。

int h = Height;
int w = Width;

在这里,我们确定窗口的宽度和高度。

ptr.Translate(new QPoint(w/2, h/2));

我们将坐标系移到窗口的中间。 这样,我们使绘图在数学上更容易。

for (double rot=0; rot < 360.0; rot+=5.0 ) 
{
    ptr.DrawEllipse(-125, -40, 250, 80);
    ptr.Rotate(5.0);
}

我们绘制一个椭圆对象 72 次。 每次,我们将椭圆旋转 5 度。 这将创建我们的甜甜圈形状。

Donut

图:多纳圈

灰度图像

在下面的示例中,我们将创建一个灰度图像。

using System;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this example, we create a 
 * grayscale image.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{    
    QImage sid;
    int w, h = 0;

    public QyotoApp() 
    {
        WindowTitle = "Gray scale";

        PaintEvent += OnPaintEvent;        

        LoadImage();
        Resize(320, 150);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    { 
        QPainter ptr = new QPainter(this);
        DrawImages(ptr);

        ptr.End();
    }

    void DrawImages(QPainter ptr) 
    {
        ptr.DrawImage(5, 15, sid);
        ptr.DrawImage(w + 10, 15, GrayScale(sid.Copy()));
    }

    void LoadImage()
    {
        sid = new QImage("smallsid.jpg");

        w = sid.Width();
        h = sid.Height();
    }

    QImage GrayScale(QImage img)
    {        
        for (int i=0; i < w; i++)
        {
            for (int j=0; j < h; j++)
            {
                uint c = img.Pixel(i, j);
                int gray = Global.qGray(c);
                int alpha = Global.qAlpha(c);
                img.SetPixel(i, j, Global.qRgba(gray, gray, 
                   gray, alpha));                
            }
        }  

        return img;
    }          

    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们有一个彩色 JPG 图像。 我们把它画在窗口上。 我们创建图像的副本,将其转换为灰度并在原始图像旁边的窗口上绘制。

void LoadImage()
{
    sid = new QImage("smallsid.jpg");

    w = sid.Width();
    h = sid.Height();
}

LoadImage()方法中,我们加载图像并获取其宽度和高度。

QImage GrayScale(QImage img)
{        
    for (int i=0; i < w; i++)
    {
        for (int j=0; j < h; j++)
        {
            uint c = img.Pixel(i, j);
            int gray = Global.qGray(c);
            int alpha = Global.qAlpha(c);
            img.SetPixel(i, j, Global.qRgba(gray, gray, 
                gray, alpha));                
        }
    }  

    return img;
}    

GrayScale()方法将图像转换为灰度并返回。 我们遍历图像的所有像素。 Pixel()方法返回有问题的像素。 我们使用Global.qGray()方法来获取特定像素的灰度值。 同样,我们获得 alpha 值。 最后,我们使用SetPixel()方法修改像素。 我们将灰色值用于颜色的红色,绿色和蓝色部分。

Grayscale image

图:灰度图像

反射

在下一个示例中,我们显示反射图像。 该效果使人产生幻觉,好像图像在水中被反射一样。

using System;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this example we create a reflected image.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{
    QImage img;
    QImage reflected_img;

    int iw, ih = 0;
    double initial_opacity = 0.7;
    double opacity = 0.7;
    double step = 0;
    const int GAP = 30;

    public QyotoApp() 
    {
        WindowTitle = "Reflection";

        PaintEvent += OnPaintEvent;

        InitExample();  

        Resize(300, 400);
        Move(150, 150);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    { 
        QPainter ptr = new QPainter(this);
        DrawImages(ptr);

        ptr.End();
    }

    void InitExample()
    {
        img = new QImage("slanec.png");

        if (img.IsNull()) 
        {
            Console.WriteLine("Error loading image");
        }

        iw = img.Width();
        ih = img.Height();

        step = opacity / ih;    

        reflected_img = new QImage(iw, ih, QImage.Format.Format_RGB32);
        CreateReflectedImage();
    }       

    void CreateReflectedImage()
    {
        QPainter fptr = new QPainter(reflected_img);

        int i = 0;
        double opacity = 0.7;    

        while (i < ih)
        {        
            i++;
            opacity = opacity - step;

            fptr.Opacity = initial_opacity-opacity;
            fptr.DrawImage(0, i, img, 0, i, -1, 1);
        }          

        fptr.End();
    }

    void DrawImages(QPainter ptr) 
    {
        int w = Width;
        int h = Height;

        ptr.FillRect(0, 0, w, h, Qt.GlobalColor.black);
        ptr.SetRenderHint(QPainter.RenderHint.Antialiasing);

        QRect r = new QRect(25, 15, iw, ih);
        ptr.DrawImage(r, img);

        ptr.Translate(0, 2 * ih + GAP);
        ptr.Scale(1, -1);     

        ptr.DrawImage(25, 0, reflected_img);      
    }

    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们从当前工作目录加载图像。 我们创建另一个相同大小的空图像。 我们将原始图像逐行复制到新的空白图像,并逐渐增加透明度。

img = new QImage("slanec.png");

if (img.IsNull()) 
{
    Console.WriteLine("Error loading image");
}

我们加载一个 PNG 图片,并进行一些错误检查。

iw = img.Width();
ih = img.Height();

step = opacity / ih;     

我们得到图像的宽度和高度。 步进变量控制第二张图像淡出的强度。

reflected_img = new QImage(iw, ih, QImage.Format.Format_RGB32);

创建一个新的空图像。 它具有原始图像的大小。

void CreateReflectedImage()
{
    QPainter fptr = new QPainter(reflected_img);
    ...

CreateReflectedImage()方法中,我们绘制空白图像。

while (i < ih)
{        
    i++;
    opacity = opacity - step;

    fptr.Opacity = initial_opacity-opacity;
    fptr.DrawImage(0, i, img, 0, i, -1, 1);
}     

我们将原始图像复制到新图像。 逐行。 不透明度在每个循环中逐步降低。

QRect r = new QRect(25, 15, iw, ih);
ptr.DrawImage(r, img);

第一个图像绘制在窗口上。

ptr.Translate(0, 2 * ih + GAP);
ptr.Scale(1, -1);     

ptr.DrawImage(25, 0, reflected_img);   

在这里,我们将第二个图像向下移动,比原始图像低一些。 Scale()方法将图像上下翻转。 请注意,平移是图像高度的两倍。 这是必要的,因为缩放操作不仅会翻转图像,还会使图像向上移动。 要了解这一点,只需拍摄一张照片,将其放在桌子上并翻转即可。

A reflected image

图:反射图像

等待效果

在此示例中,我们使用透明效果创建一个等待演示。 我们将绘制 8 条线,这些线将逐渐消失,从而产生一条线在移动的错觉。 此类效果通常用于通知用户幕后正在进行繁重的任务。 一个示例是通过互联网流式传输视频。

using System;
using QtGui;
using QtCore;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program draws basic shapes
 * available in Qyoto.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified November 2012
 */

public class QyotoApp : QMainWindow 
{
    int count = 0;

    double[,] trs = 
    {
        { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
        { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
        { 0.9, 1.0,  0.0,  0.15, 0.3, 0.5, 0.65, 0.8 },
        { 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5, 0.65 },
        { 0.65, 0.8, 0.9,  1.0,  0.0,  0.15, 0.3, 0.5 },
        { 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15, 0.3 },
        { 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0,  0.15 },
        { 0.15, 0.3, 0.5, 0.65, 0.8, 0.9, 1.0,  0.0 }
    };

    public QyotoApp() 
    {
        WindowTitle = "Waiting";

        PaintEvent += OnPaintEvent;

        InitExample();

        Resize(300, 200);
        Move(300, 300);
        Show();
    }

    private void OnPaintEvent(object sender, QEventArgs<QPaintEvent> e)
    {
        QPainter ptr = new QPainter(this);
        DrawLines(ptr);

        ptr.End();
    }

    void InitExample()
    {    
        count = 0;
        StartTimer(105);
    }

    void DrawLines(QPainter ptr)
    {
        QPen pen = new QPen();
        pen.Width = 3;
        pen.CapStyle = PenCapStyle.RoundCap;

        int w = Width;
        int h = Height;

        ptr.Translate(w/2, h/2);
        ptr.Pen = pen;

        int len = trs.GetLength(0);

        for (int i=0; i < len; i++)
        {
            ptr.Opacity = trs[count%8, i];
            ptr.DrawLine(0, -10, 0, -40);
            ptr.Rotate(45);
        }
    }

    protected override void OnTimerEvent(QTimerEvent e)
    {
        count++;
        Repaint();
    }

    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

我们用八个不同的 alpha 值绘制八条线。

double[,] trs = 
{
    { 0.0, 0.15, 0.30, 0.5, 0.65, 0.80, 0.9, 1.0 },
    { 1.0, 0.0,  0.15, 0.30, 0.5, 0.65, 0.8, 0.9 },
...

这是透明度值的数组。 有 8 行,每行一个位置。 8 行中的每行将连续使用这些值。

count = 0;
StartTimer(105);

在这里,我们启动计数值并启动一个计时器。

QPen pen = new QPen();
pen.Width = 3;
pen.CapStyle = PenCapStyle.RoundCap;

我们使线条更粗一些,以使它们更加可见。 我们用圆帽画线。 带圆帽的线条看起来更好。

for (int i=0; i < len; i++)
{
    ptr.Opacity = trs[count%8, i];
    ptr.DrawLine(0, -10, 0, -40);
    ptr.Rotate(45);
}

在此循环中,我们设置不透明度值。 我们画线并旋转它。 这产生了移动和渐隐线的错觉。

protected override void OnTimerEvent(QTimerEvent e)
{
    count++;
    Repaint();
}

每次调用计时器事件时,我们都会增加计数值并重新绘制窗口区域。

Waiting effect

图:等待 effect

在 Qyoto C# 编程教程的这一部分中,我们结束了有关在 Qyoto 中绘图的讨论。

Qyoto 中的自定义小部件

原文: http://zetcode.com/gui/csharpqyoto/customwidget/

在 Qyoto C# 编程教程的这一部分中,我们将展示如何创建自定义窗口小部件。

大多数工具包通常仅提供最常用的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 程序员必须自己创建此类小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。

在本章中,我们将创建两个自定义窗口小部件。 刻录小部件和 Led 小部件。

刻录小部件

在下一个示例中,我们将创建一个自定义刻录小部件。 可以在 Nero 或 K3B 之类的应用中看到此小部件。 该小部件将从头开始创建。

burning.cs

using System;
using QtCore;
using QtGui;

public class Burning : QWidget 
{
    const int PANEL_HEIGHT = 30;
    const int DISTANCE = 19;
    const int LINE_WIDTH = 5;
    const int DIVISIONS = 10;
    const float FULL_CAPACITY = 700f;
    const float MAX_CAPACITY = 750f;

    QColor redColor = new QColor(255, 175, 175);
    QColor yellowColor = new QColor(255, 255, 184);

    QWidget parent;

    String[] num = 
    {
        "75", "150", "225", "300",
        "375", "450", "525", "600",
        "675"
    };

    public Burning(QWidget parent) 
    {
        this.parent = parent;
        MinimumHeight = PANEL_HEIGHT;
    }

    protected override void OnPaintEvent(QPaintEvent pe) 
    {
        QPainter ptr = new QPainter(this);

        DrawWidget(ptr);
        ptr.End();
    }

    void DrawWidget(QPainter ptr) 
    {
        QyotoApp burn = (QyotoApp) parent;

        float slid_width = burn.GetCurrentWidth();
        float width = Size.Width;
        float step = width / DIVISIONS;

        float till = (width / MAX_CAPACITY) * slid_width;
        float full = (width / MAX_CAPACITY) * FULL_CAPACITY;

        if (slid_width > FULL_CAPACITY) 
        {
            ptr.Pen = yellowColor;
            ptr.Brush = yellowColor;
            ptr.DrawRect(new QRectF(0, 0, full, PANEL_HEIGHT));
            ptr.Pen = redColor;
            ptr.Brush = redColor;
            ptr.DrawRect(new QRectF(full+1, 0, till-full, PANEL_HEIGHT));

        } else 
        {
            if (slid_width > 0) 
            {
               ptr.Pen = yellowColor;
               ptr.Brush = yellowColor;
               ptr.DrawRect(new QRectF(0, 0, till, PANEL_HEIGHT));
            }
        }

        ptr.Pen = new QColor(90, 90, 90);
        ptr.SetBrush(BrushStyle.NoBrush);
        ptr.DrawRect(0, 0, Size.Width-1, PANEL_HEIGHT-1);

        QFont newFont = ptr.Font;
        newFont.PointSize = 7;
        ptr.Font = newFont;

        QFontMetrics metrics = new QFontMetrics(newFont);

        for (int i = 1; i <= num.Length; i++) 
        {
            ptr.DrawLine(new QLineF(i*step, 1, i*step, LINE_WIDTH));

            int w = metrics.Width(num[i-1]);
            ptr.DrawText(new QPointF(i*step-w/2, DISTANCE), num[i-1]);
        }        
    }
}

在这个文件中,我们创建了刻录小部件。

public class Burning : QWidget 
{
...

自定义窗口小部件基于QWidget类。

const int PANEL_HEIGHT = 30;
const int DISTANCE = 19;
const int LINE_WIDTH = 5;
const int DIVISIONS = 10;
const float FULL_CAPACITY = 700f;
const float MAX_CAPACITY = 750f;

这些是重要的常数。 PANEL_HEIGHT定义自定义窗口小部件的高度。 DISTANCE是比例尺上的数字与其父边框顶部之间的距离。 LINE_WIDTH是垂直线的宽度。 DIVISIONS是秤的数量。 FULL_CAPACITY是媒体的容量。 达到目标后,就会发生过度刻录。 这通过红色可视化。 MAX_CAPACITY是介质的最大容量。

String[] num = 
{
    "75", "150", "225", "300",
    "375", "450", "525", "600",
    "675"
};

我们使用这些数字来构建刻录小部件的比例。

protected override void OnPaintEvent(QPaintEvent pe) 
{
    QPainter ptr = new QPainter(this);

    DrawWidget(ptr);
    ptr.End();
}

自定义窗口小部件的图形委托给DrawWidget()方法。

QyotoApp burn = (QyotoApp) parent;

我们检索对父窗口小部件的引用。

float slid_width = burn.GetCurrentWidth();

我们使用它来获取当前选定的滑块值。

float width = Size.Width;

我们得到小部件的宽度。 自定义窗口小部件的宽度是动态的。 用户可以调整大小。

float till = (width / MAX_CAPACITY) * slid_width;
float full = (width / MAX_CAPACITY) * FULL_CAPACITY;

我们使用width变量进行转换。 在比例尺值和自定义小部件的度量之间。 请注意,我们使用浮点值。 我们在绘图中获得了更高的精度。

ptr.Pen = redColor;
ptr.Brush = redColor;
ptr.DrawRect(new QRectF(full+1, 0, till-full, PANEL_HEIGHT));

这三行画出红色矩形,表示过度燃烧。

ptr.DrawRect(0, 0, Size.Width-1, PANEL_HEIGHT-1);

这是小部件的周长。 外部矩形。

ptr.DrawLine(new QLineF(i*step, 1, i*step, LINE_WIDTH));

在这里,我们画出小的垂直线。

QFontMetrics metrics = new QFontMetrics(newFont);
...
int w = metrics.Width(num[i-1]);
ptr.DrawText(new QPointF(i*step-w/2, DISTANCE), num[i-1]);

在这里,我们在比例尺上绘制数字。 为了精确定位数字,我们必须获得字符串的宽度。

main.cs

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, we create
 * a custom Burning widget.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    const int MAX_CAPACITY = 750;

    QSlider slider;
    QWidget widget;
    int cur_width;

    public QyotoApp() 
    {
        WindowTitle = "The Burning Widget";

        InitUI();

        Resize(370, 200);
        Move(300, 300);
        Show();
    }

    void InitUI() 
    {       
       slider = new QSlider(Qt.Orientation.Horizontal , this);
       slider.Maximum = MAX_CAPACITY;
       slider.SetGeometry(50, 50, 130, 30);

       slider.ValueChanged += OnValueChanged;

       QVBoxLayout vbox = new QVBoxLayout(this);
       QHBoxLayout hbox = new QHBoxLayout();

       vbox.AddStretch(1);

       widget = new Burning(this);
       hbox.AddWidget(widget, 0);

       vbox.AddLayout(hbox);

       Layout = vbox;
    }

    [Q_SLOT]
    void OnValueChanged(int val) 
    {
        cur_width = val;
        widget.Repaint();
    }

    public int GetCurrentWidth() 
    {
        return cur_width;
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();
        return QApplication.Exec();
    }
}

这是主文件。 在这里,我们创建滑块小部件并使用我们的自定义小部件。

widget = new Burning(this);
hbox.AddWidget(widget, 0);

我们创建了刻录小部件的实例,并将其添加到水平框中。

[Q_SLOT]
void OnValueChanged(int val) 
{
    cur_width = val;
    widget.Repaint();
}

当滑块的值更改时,我们将其存储在cur_width变量中,然后重新绘制自定义窗口小部件。

public int GetCurrentWidth() 
{
    return cur_width;
}

定制小部件调用此方法以获取实际的滑块值。

The Burning widget

图:刻录小部件

Led 小部件

Led 小部件是一个灯泡,可以将其设置为不同的颜色。 在我们的例子中是红色,绿色,橙色和黑色。 该自定义窗口小部件仅使用 SVG 图像创建。 有四个 SVG 图像。 每个用于 Led 小部件的一种状态。

要编译该示例,我们需要引用qyoto-qtsvg.dll库。 例如,在我们的系统上,我们将-r/usr/local/lib/mono/qyoto/qyoto-qtsvg.dll添加到了编译选项。

led.cs

using System;
using QtCore;
using QtGui;
using QtSvg;

public class Led : QWidget 
{
    string[] cols;
    int col;

    public Led(QWidget parent) 
    {
        const int GREEN = 1;
        col = GREEN;

        SetMinimumSize(50, 50);
        SetMaximumSize(50, 50);

        cols = new string[] { "red.svg", "green.svg",  
            "orange.svg", "black.svg" };
    }

    public void SetColour(int newColour)
    {
        col = newColour;
        Update();
    }

    protected override void OnPaintEvent(QPaintEvent e) 
    {
        QPainter ptr = new QPainter(this);

        DrawCustomWidget(ptr);
        ptr.End();
    }

    void DrawCustomWidget(QPainter ptr) 
    {
        QSvgRenderer srnd = new QSvgRenderer();
        srnd.Load(cols[col]);
        srnd.Render(ptr);       
    }
}

led.cs类中,我们构建了自定义窗口小部件。

const int GREEN = 1;
col = GREEN;

当一切正常时,GREEN常量指示 Led 小部件的状态。 颜色变量定义窗口小部件的当前状态。

SetMinimumSize(50, 50);
SetMaximumSize(50, 50);

这两条线强制窗口小部件具有恒定的大小。 SVG 图像的大小为50x50

cols = new string[] { "red.svg", "green.svg",  
    "orange.svg", "black.svg" };

我们将 SVG 图像文件名存储在cols数组中。

public void SetColour(int newColour)
{
    col = newColour;
    Update();
}

SetColour()方法将col变量设置为新值。 我们调用Update()方法重绘 Led 小部件以反映新状态。

void DrawCustomWidget(QPainter ptr) 
{
    QSvgRenderer srnd = new QSvgRenderer();
    srnd.Load(cols[col]);
    srnd.Render(ptr);       
}

DrawCustomWidget()方法中,我们使用QSvgRenderer类显示 SVG 图像。

main.cs

using Qyoto;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * This program creates a custom Led
 * widget.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QWidget 
{
    const int RED = 0;
    const int GREEN = 1;
    const int ORANGE = 2;
    const int BLACK = 3;

    Led led;

    public QyotoApp() 
    {
        WindowTitle = "Led widget";

        SetupUI();

        Resize(250, 150);
        Move(300, 300);
        Show();
    }

    public void SetupUI() 
    {        
        QVBoxLayout vbox = new QVBoxLayout();
        QHBoxLayout hbox = new QHBoxLayout();

        led = new Led(this);

        hbox.AddWidget(led);
        vbox.AddStretch(1);
        vbox.AddLayout(hbox);
        vbox.AddStretch(1);

        QHBoxLayout hbox2 = new QHBoxLayout();

        QPushButton pb1 = new QPushButton("Normal", this);
        QPushButton pb2 = new QPushButton("Warning", this);
        QPushButton pb3 = new QPushButton("Emergency", this);
        QPushButton pb4 = new QPushButton("Off", this);

        hbox2.AddWidget(pb1);
        hbox2.AddWidget(pb2);
        hbox2.AddWidget(pb3);
        hbox2.AddWidget(pb4);

        vbox.AddLayout(hbox2);

        Connect(pb1, SIGNAL("clicked()"), this, SLOT("OnClicked()"));
        Connect(pb2, SIGNAL("clicked()"), this, SLOT("OnClicked()"));
        Connect(pb3, SIGNAL("clicked()"), this, SLOT("OnClicked()"));
        Connect(pb4, SIGNAL("clicked()"), this, SLOT("OnClicked()"));

        Layout = vbox;
    }

    [Q_SLOT]
    public void OnClicked() 
    {

        QPushButton sender = (QPushButton) this.Sender();
        string text = sender.Text;

        if (text == "Normal") 
        {
            led.SetColour(GREEN);
        } 
        else if (text == "Warning")
        {
            led.SetColour(ORANGE);
        } 
        else if (text == "Emergency")
        {
            led.SetColour(RED);
        } 
        else if (text == "Off")
        {
            led.SetColour(BLACK);        
        }
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();

        return QApplication.Exec();
    }
}

这是main.cs文件。 我们连续有四个按钮,窗口中央有一个 Led 小部件。 这四个按钮控制 Led 小部件的状态。 Led 小部件有四个状态。 正常,警告,紧急和关闭。

led = new Led(this);

hbox.AddWidget(led);

我们创建 Led 小部件的实例并将其放入水平框中。

else if ( text == "Warning")
{
    led.SetColour(ORANGE);
} 

如果单击警告按钮,则 LED 小部件的颜色将变为橙色。 更准确地说,将加载并显示一个新的橙色 SVG 图像。

The Led widget

图:Led 小部件显示“关闭”状态

在 Qyoto C# 教程的这一部分中,我们演示了如何创建自定义窗口小部件。

贪食蛇

原文: http://zetcode.com/gui/csharpqyoto/nibbles/

在 Qyoto C# 编程教程的这一部分中,我们将创建贪食蛇游戏克隆。

Nibbles是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。

开发

蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 游戏结束后,我们在窗口中心显示"Game Over"消息。

board.cs

using System;
using QtCore;
using QtGui;

public class Board : QFrame 
{
    const int WIDTH = 300;
    const int HEIGHT = 300;
    const int DOT_SIZE = 10;
    const int ALL_DOTS = 900;
    const int RAND_POS = 30;
    const int DELAY = 140;

    int[] x = new int[ALL_DOTS];
    int[] y = new int[ALL_DOTS];

    int dots;
    int apple_x;
    int apple_y;

    bool left = false;
    bool right = true;

    bool up = false;
    bool down = false;
    bool inGame = true;

    QBasicTimer timer;
    QImage ball;
    QImage apple;
    QImage head;

    public Board() 
    {        
        StyleSheet = "QWidget { background-color: black }";

        FocusPolicy = Qt.FocusPolicy.StrongFocus;

        ball = new QImage("dot.png");
        apple = new QImage("apple.png");
        head = new QImage("head.png");

        InitGame();
    }

    void InitGame() 
    {
        dots = 3;

        for (int z = 0; z < dots; z++) {
            x[z] = 50 - z*10;
            y[z] = 50;
        }

        LocateApple();

        timer = new QBasicTimer();
        timer.Start(DELAY, this);
    }

    protected override void OnPaintEvent(QPaintEvent e)
    {
        QPainter painter = new QPainter();
        painter.Begin(this);

        if (inGame) 
        {
            DrawObjects(painter);
        } else {
            GameOver(painter);
        }

        painter.End();
    }

    void DrawObjects(QPainter painter) 
    {
        painter.DrawImage(apple_x, apple_y, apple);

        for (int z = 0; z < dots; z++) 
        {
            if (z == 0)
                painter.DrawImage(x[z], y[z], head);
            else painter.DrawImage(x[z], y[z], ball);
        }
    }

    void GameOver(QPainter painter) 
    {
        String msg = "Game Over";
        QFont small = new QFont("Helvetica", 12,
            (int) QFont.Weight.Bold);
        QFontMetrics metr = new QFontMetrics(small);

        int textWidth = metr.Width(msg);
        int h = Height;
        int w = Width;

        painter.SetPen(GlobalColor.white);
        painter.Font = small;
        painter.Translate(new QPoint(w/2, h/2));
        painter.DrawText(-textWidth/2, 0, msg);
    }

    void CheckApple() 
    {
        if ((x[0] == apple_x) && (y[0] == apple_y)) 
        {
            dots++;
            LocateApple();
        }
    }

    void Move() 
    {
        for (int z = dots; z > 0; z--) 
        {
            x[z] = x[(z - 1)];
            y[z] = y[(z - 1)];
        }

        if (left) 
        {
            x[0] -= DOT_SIZE;
        }

        if (right) 
        {
            x[0] += DOT_SIZE;
        }

        if (up)
        {
            y[0] -= DOT_SIZE;
        }

        if (down) 
        {
            y[0] += DOT_SIZE;
        }
    }

    void CheckCollision() 
    {
        for (int z = dots; z > 0; z--) 
        {
            if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) 
            {
                inGame = false;
            }
        }

        if (y[0] > HEIGHT) 
        {
            inGame = false;
        }

        if (y[0] < 0) 
        {
            inGame = false;
        }

        if (x[0] > WIDTH) 
        {
            inGame = false;
        }

        if (x[0] < 0) 
        {
            inGame = false;
        }
    }

    void LocateApple() 
    {
        Random rand = new Random();

        int r = (int) (rand.Next(RAND_POS));
        apple_x = ((r * DOT_SIZE));
        r = (int) (rand.Next(RAND_POS));
        apple_y = ((r * DOT_SIZE));
    }

    protected override void OnTimerEvent(QTimerEvent arg1) 
    {
        if (inGame) 
        {
            CheckApple();
            CheckCollision();
            Move();
        } else 
        {
            timer.Stop();
        }

        Repaint();
    }

    protected override void OnKeyPressEvent(QKeyEvent e)
    {        
        int key = e.Key();

        if (key == (int) Qt.Key.Key_Left && !right) 
        {
            left = true;
            up = false;
            down = false;
        }

        if ((key == (int) Qt.Key.Key_Right) && !left) 
        {
            right = true;
            up = false;
            down = false;            
        }

        if ((key == (int) Qt.Key.Key_Up) && !down) 
        {
            up = true;
            right = false;
            left = false;            
        }

        if ((key == (int) Qt.Key.Key_Down) && !up) 
        {
            down = true;
            right = false;
            left = false;       
        }
    }
}

首先,我们将定义一些在游戏中使用的全局变量。

WIDTHHEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。

int[] x = new int[ALL_DOTS];
int[] y = new int[ALL_DOTS];

这两个数组存储蛇的所有可能关节的 x,y 坐标。

InitGame()方法初始化变量,加载图像并启动超时功能。

if (inGame) 
{
    DrawObjects(painter);
} else {
    GameOver(painter);
}

PaintEvent()方法内部,我们检查inGame变量。 如果为真,则绘制对象。 苹果和蛇的关节。 否则,我们显示"Game Over"文本。

void DrawObjects(QPainter painter) 
{
    painter.DrawImage(apple_x, apple_y, apple);

    for (int z = 0; z < dots; z++) 
    {
        if (z == 0)
            painter.DrawImage(x[z], y[z], head);
        else painter.DrawImage(x[z], y[z], ball);
    }
}

DrawObjects()方法绘制苹果和蛇的关节。 蛇的第一个关节是其头部,用红色圆圈表示。

void CheckApple() 
{
    if ((x[0] == apple_x) && (y[0] == apple_y)) 
    {
        dots++;
        LocateApple();
    }
}

CheckApple()方法检查蛇是否击中了苹果对象。 如果是这样,我们添加另一个蛇形关节并调用LocateApple()方法,该方法将随机放置一个新的Apple对象。

Move()方法中,我们有游戏的关键算法。 要了解它,请看一下蛇是如何运动的。 您控制蛇的头。 您可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。

for (int z = dots; z > 0; z--)
{
    x[z] = x[(z - 1)];
    y[z] = y[(z - 1)];
}

该代码将关节向上移动。

if (left) 
{
    x[0] -= DOT_SIZE;
}

将头向左移动。

CheckCollision()方法中,我们确定蛇是否击中了自己或撞墙之一。

for (int z = dots; z > 0; z--) 
{
    if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) 
    {
        inGame = false;
    }
}

如果蛇用头撞到关节之一,我们就结束游戏。

if (y[0] > HEIGHT) 
{
    inGame = false;
}

如果蛇击中了棋盘的底部,我们就结束了游戏。

LocateApple()方法在板上随机放置一个苹果。

Random rand = new Random();

int r = (int) (rand.Next(RAND_POS));

我们得到一个从 0 到RAND_POS-1的随机数。

apple_x = ((r * DOT_SIZE));
...
apple_y = ((r * DOT_SIZE));

这些行设置了 apple 对象的 x,y 坐标。

if (inGame) 
{
    CheckApple();
    CheckCollision();
    Move();
} else 
{
    timer.Stop();
}

每 140 毫秒,将调用TimerEvent()方法。 如果我们参与了游戏,我们将调用三种构建游戏逻辑的方法。 否则,我们将停止计时器。

在 Board 类的KeyPressEvent()方法中,我们确定按下的键。

if (key == (int) Qt.Key.Key_Left && !right) 
{
    left = true;
    up = false;
    down = false;
}

如果单击左光标键,则将left变量设置为true。 在Move()方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。

nibbles.cs

using System;
using QtCore;
using QtGui;

/**
 * ZetCode Qyoto C# tutorial
 *
 * In this program, we create
 * a Nibbles game clone.
 *
 * @author Jan Bodnar
 * website zetcode.com
 * last modified October 2012
 */

public class QyotoApp : QMainWindow 
{    
    public QyotoApp() 
    {
        WindowTitle = "Nibbles";

        CentralWidget= new Board();

        Resize(310, 310);
        Move(300, 300);
        Show();
    }

    [STAThread]
    public static int Main(String[] args) 
    {
        new QApplication(args);
        new QyotoApp();

        return QApplication.Exec();
    }
}

在这个类中,我们设置了贪食蛇游戏。

Nibbles

图:贪食蛇

这是用 Qyo​​to 库和 C# 编程语言编程的贪食蛇电脑游戏。

Ruby Qt 教程

原文: http://zetcode.com/gui/rubyqt/

这是 Ruby Qt 教程。 在本教程中,您将学习使用 Ruby 语言在 Qt 中进行 GUI 编程的基础。 本教程适合初学者和中级程序员。

目录

Qt

Qt 是一个跨平台的应用开发框架。 用 Qt 开发的一些知名应用是 KDE,Opera,Google Earth 和 Skype。 Qt 于 1995 年 5 月首次公开发布。它具有双重许可。 这意味着,它可以用于创建开源应用以及商业应用。 Qt 工具箱是一个非常强大的工具箱。 它在开源社区中已经建立。

Tweet

相关教程

在 ZetCode 上有完整的 Ruby 教程Ruby GTK 教程是 Ruby 支持的另一个 GUI 库的教程。 Qt4 教程以 C++ 语言展示了 Qt 库。

Ruby Qt 简介

原文: http://zetcode.com/gui/rubyqt/introduction/

在 Ruby Qt 教程的这一部分中,我们将介绍 Qt 工具包并使用 Ruby 编程语言创建第一个程序。

本教程的目的是帮助您开始使用 Ruby 语言的 Qt 工具包。 可以在此处下载本教程中使用的图像。 我们使用了 Gnome 项目的 Tango 图标包中的一些图标。

关于

Qt 是用于创建图形用户界面的领先工具包之一。 Ruby 是一种流行的脚本语言。

创建工具提示

第一个示例将显示一个工具提示。 工具提示是一个小的矩形窗口,它提供有关对象的简短信息。 它通常是一个 GUI 组件。 它是应用帮助系统的一部分。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This code shows a tooltip on 
# a window.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Tooltip"

        setToolTip "This is Qt::Widget"

        resize 250, 150
        move 300, 300

        show
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

该示例创建一个窗口。 如果将鼠标指针悬停在窗口区域上方,则会弹出一个工具提示。

require 'Qt'

require关键字导入我们将在应用中使用的必要类型。

class QtApp < Qt::Widget

该示例继承自Qt::WidgetWidget类是所有用户界面对象的基类。 小部件是用户界面的原子。 它从窗口系统接收鼠标,键盘和其他事件。

setWindowTitle "Tooltip"

此方法调用为窗口创建标题。

setToolTip "This is Qt::Widget"

setToolTip方法为Widget对象创建工具提示。

resize 250, 150

在这里,我们设置窗口的宽度和高度。

move 300, 300

move方法在屏幕上移动窗口。

show

一切准备就绪后,我们在屏幕上显示窗口。

app = Qt::Application.new ARGV
QtApp.new
app.exec

这三行设置了应用。

Tooltip

图:工具提示

使窗口居中

在第二个示例中,我们将窗口置于屏幕中央。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program centers a window
# on the screen.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

WIDTH = 250
HEIGHT = 150

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Center"
        resize WIDTH, HEIGHT

        center
        show
    end

    def center
        qdw = Qt::DesktopWidget.new

        screenWidth = qdw.width
        screenHeight = qdw.height

        x = (screenWidth - WIDTH) / 2
        y = (screenHeight - HEIGHT) / 2

        move x, y
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

Qt 工具包没有一种将窗口居中的方法。

WIDTH = 250
HEIGHT = 150

这两个常数定义了应用窗口的宽度和高度。

qdw = Qt::DesktopWidget.new

Qt::DesktopWidget类提供有关屏幕的信息。

screenWidth = qdw.width
screenHeight = qdw.height

在这里,我们确定屏幕的宽度和高度。

x = (screenWidth - WIDTH) / 2
y = (screenHeight - HEIGHT) / 2

在这里,我们计算居中窗口的xy坐标。 为了使窗口在屏幕上居中,我们需要知道屏幕的大小和窗口的大小。

move x, y

我们将窗口移至计算出的 x 和 y 坐标。

退出按钮

在本节的最后一个示例中,我们将创建一个退出按钮。 当我们按下此按钮时,应用终止。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program creates a quit
# button. When we press the button,
# the application terminates. 
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Quit button"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui    
        quit = Qt::PushButton.new 'Quit', self
        quit.resize 80, 30
        quit.move 50, 50
        connect quit, SIGNAL('clicked()'), $qApp, SLOT('quit()')
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

Qt::PushButton类在 Ruby Qt 中显示一个按钮。 它是一个矩形小部件,通常显示一个文本标签。

init_ui

我们将用户界面的创建委托给init_ui方法。

quit = Qt::PushButton.new 'Quit', self

我们创建按钮小部件。 构造器的第一个参数是按钮显示的标签。 第二个参数是按钮的父窗口小部件。

quit.resize 80, 30
quit.move 50, 50

我们调整和放置按钮小部件的大小。

connect quit, SIGNAL('clicked()'), $qApp, SLOT('quit()')

单击退出按钮时,将发出clicked信号。 connect方法将信号连接到对象的特定槽。 在我们的情况下,它是应用对象的quit方法。 $qApp是指向应用实例的全局指针。

Quit button

图:退出按钮

本节介绍了使用 Ruby 语言的 Qt 工具包。

PyQt5 中的绘图

原文: http://zetcode.com/gui/pyqt5/painting/

PyQt5 绘图系统能够呈现向量图形,图像和轮廓基于字体的文本。 当我们想要更改或增强现有的小部件,或者从头开始创建自定义小部件时,应用中需要绘图。 要进行绘制,我们使用 PyQt5 工具包提供的绘制 API。

QPainter

QPainter在小部件和其他绘图设备上执行低级绘图。 它可以绘制从简单的线条到复杂形状的所有内容。

paintEvent方法

绘图是在paintEvent()方法中完成的。 绘图代码位于QPainter对象的begin()end()方法之间。 它在小部件和其他绘图设备上执行低级绘图。

绘制文字

我们首先在窗口的客户区域上绘制一些 Unicode 文本。

drawingtext.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

In this example, we draw text in Russian Cylliric.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

import sys
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QFont
from PyQt5.QtCore import Qt

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.text = "Лев Николаевич Толстой\nАнна Каренина"

        self.setGeometry(300, 300, 280, 170)
        self.setWindowTitle('Drawing text')
        self.show()

    def paintEvent(self, event):

        qp = QPainter()
        qp.begin(self)
        self.drawText(event, qp)
        qp.end()

    def drawText(self, event, qp):

        qp.setPen(QColor(168, 34, 3))
        qp.setFont(QFont('Decorative', 10))
        qp.drawText(event.rect(), Qt.AlignCenter, self.text)        

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们以西里尔字母绘制一些文本。 文本在垂直和水平方向上对齐。

def paintEvent(self, event):
...

绘制是在绘画事件中完成的。

qp = QPainter()
qp.begin(self)
self.drawText(event, qp)
qp.end()

QPainter类负责所有低级绘图。 所有绘图方法都在begin()end()方法之间。 实际绘图将委托给drawText()方法。

qp.setPen(QColor(168, 34, 3))
qp.setFont(QFont('Decorative', 10))

在这里,我们定义了用于绘制文本的笔和字体。

qp.drawText(event.rect(), Qt.AlignCenter, self.text)

drawText()方法在窗口上绘制文本。 绘画事件的rect()方法返回需要更新的矩形。 使用Qt.AlignCenter,我们可以在两个维度上对齐文本。

Drawing text

图:绘制文本

绘制点

点是可以绘制的最简单的图形对象。 这是窗口上的一个小地方。

points.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

In the example, we draw randomly 1000 red points 
on the window.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import Qt
import sys, random

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.setGeometry(300, 300, 300, 190)
        self.setWindowTitle('Points')
        self.show()

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        self.drawPoints(qp)
        qp.end()

    def drawPoints(self, qp):

        qp.setPen(Qt.red)
        size = self.size()

        for i in range(1000):
            x = random.randint(1, size.width()-1)
            y = random.randint(1, size.height()-1)
            qp.drawPoint(x, y)     

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们在窗口的客户区域上随机绘制了 1000 个红点。

qp.setPen(Qt.red)

我们将笔设置为红色。 我们使用预定义的Qt.red颜色常量。

size = self.size()

每次我们调整窗口大小时,都会生成一个绘制事件。 我们使用size()方法获得窗口的当前大小。 我们使用窗口的大小将点分布在整个窗口的客户区域中。

qp.drawPoint(x, y) 

我们用drawPoint()方法画点。

Points

图:点

颜色

颜色是代表红色,绿色和蓝色(RGB)强度值的组合的对象。 有效的 RGB 值在 0 到 255 之间。我们可以通过多种方式定义颜色。 最常见的是 RGB 十进制值或十六进制值。 我们还可以使用代表红色,绿色,蓝色和 Alpha 的 RGBA 值。 在这里,我们添加了一些有关透明度的额外信息。 Alpha 值为 255 表示完全不透明,0 表示完全透明,例如颜色是不可见的。

colours.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This example draws three rectangles in three
#different colours. 

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QColor, QBrush
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.setGeometry(300, 300, 350, 100)
        self.setWindowTitle('Colours')
        self.show()

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        self.drawRectangles(qp)
        qp.end()

    def drawRectangles(self, qp):

        col = QColor(0, 0, 0)
        col.setNamedColor('#d4d4d4')
        qp.setPen(col)

        qp.setBrush(QColor(200, 0, 0))
        qp.drawRect(10, 15, 90, 60)

        qp.setBrush(QColor(255, 80, 0, 160))
        qp.drawRect(130, 15, 90, 60)

        qp.setBrush(QColor(25, 0, 90, 200))
        qp.drawRect(250, 15, 90, 60)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们绘制了三个彩色矩形。

color = QColor(0, 0, 0)
color.setNamedColor('#d4d4d4')

在这里,我们使用十六进制符号定义颜色。

qp.setBrush(QColor(200, 0, 0))
qp.drawRect(10, 15, 90, 60)

在这里,我们定义了一个画笔并绘制了一个矩形。笔刷是用于绘制形状背景的基本图形对象。 drawRect()方法接受四个参数。 前两个是轴上的 x 和 y 值。 第三个和第四个参数是矩形的宽度和高度。 该方法使用当前的笔和画笔绘制矩形。

Colours

图:颜色

QPen是基本图形对象。 它用于绘制矩形,椭圆形,多边形或其他形状的线,曲线和轮廓。

pens.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

In this example we draw 6 lines using
different pen styles. 

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QPen
from PyQt5.QtCore import Qt
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.setGeometry(300, 300, 280, 270)
        self.setWindowTitle('Pen styles')
        self.show()

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        self.drawLines(qp)
        qp.end()

    def drawLines(self, qp):

        pen = QPen(Qt.black, 2, Qt.SolidLine)

        qp.setPen(pen)
        qp.drawLine(20, 40, 250, 40)

        pen.setStyle(Qt.DashLine)
        qp.setPen(pen)
        qp.drawLine(20, 80, 250, 80)

        pen.setStyle(Qt.DashDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 120, 250, 120)

        pen.setStyle(Qt.DotLine)
        qp.setPen(pen)
        qp.drawLine(20, 160, 250, 160)

        pen.setStyle(Qt.DashDotDotLine)
        qp.setPen(pen)
        qp.drawLine(20, 200, 250, 200)

        pen.setStyle(Qt.CustomDashLine)
        pen.setDashPattern([1, 4, 5, 4])
        qp.setPen(pen)
        qp.drawLine(20, 240, 250, 240)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们绘制了六条线。 线条以六种不同的笔样式绘制。 有五种预定义的笔样式。 我们还可以创建自定义笔样式。 最后一行是使用自定义笔样式绘制的。

pen = QPen(Qt.black, 2, Qt.SolidLine)

我们创建一个QPen对象。 颜色是黑色。 宽度设置为 2 像素,以便我们可以看到笔样式之间的差异。 Qt.SolidLine是预定义的笔样式之一。

pen.setStyle(Qt.CustomDashLine)
pen.setDashPattern([1, 4, 5, 4])
qp.setPen(pen)

在这里,我们定义了自定义笔样式。 我们设置Qt.CustomDashLine笔样式并调用setDashPattern()方法。 数字列表定义样式。 数字必须是偶数。 奇数定义笔划线,偶数空格。 数字越大,空格或笔划线越大。 我们的模式是 1px 笔划线,4px 间隔,5px 笔划线,4px 间隔等。

Pen styles

图:笔的样式

QBrush

QBrush是基本图形对象。 它用于绘制图形形状的背景,例如矩形,椭圆形或多边形。 笔刷可以具有三种不同类型:预定义笔刷,渐变或纹理图案。

brushes.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This example draws nine rectangles in different
brush styles.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QBrush
from PyQt5.QtCore import Qt
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.setGeometry(300, 300, 355, 280)
        self.setWindowTitle('Brushes')
        self.show()

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        self.drawBrushes(qp)
        qp.end()

    def drawBrushes(self, qp):

        brush = QBrush(Qt.SolidPattern)
        qp.setBrush(brush)
        qp.drawRect(10, 15, 90, 60)

        brush.setStyle(Qt.Dense1Pattern)
        qp.setBrush(brush)
        qp.drawRect(130, 15, 90, 60)

        brush.setStyle(Qt.Dense2Pattern)
        qp.setBrush(brush)
        qp.drawRect(250, 15, 90, 60)

        brush.setStyle(Qt.DiagCrossPattern)
        qp.setBrush(brush)
        qp.drawRect(10, 105, 90, 60)

        brush.setStyle(Qt.Dense5Pattern)
        qp.setBrush(brush)
        qp.drawRect(130, 105, 90, 60)

        brush.setStyle(Qt.Dense6Pattern)
        qp.setBrush(brush)
        qp.drawRect(250, 105, 90, 60)

        brush.setStyle(Qt.HorPattern)
        qp.setBrush(brush)
        qp.drawRect(10, 195, 90, 60)

        brush.setStyle(Qt.VerPattern)
        qp.setBrush(brush)
        qp.drawRect(130, 195, 90, 60)

        brush.setStyle(Qt.BDiagPattern)
        qp.setBrush(brush)
        qp.drawRect(250, 195, 90, 60)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们绘制了九个不同的矩形。

brush = QBrush(Qt.SolidPattern)
qp.setBrush(brush)
qp.drawRect(10, 15, 90, 60)

我们定义一个笔刷对象。 我们将其设置为绘画器对象,并通过调用drawRect()方法绘制矩形。

Brushes

图:笔刷

贝塞尔曲线

贝塞尔曲线是一条三次曲线。 可以使用QPainterPath创建 PyQt5 中的贝塞尔曲线。 画家路径是由许多图形构造块(例如矩形,椭圆形,直线和曲线)组成的对象。

beziercurve.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

This program draws a Bézier curve with 
QPainterPath.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QPainterPath
from PyQt5.QtCore import Qt
import sys

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        self.setGeometry(300, 300, 380, 250)
        self.setWindowTitle('Bézier curve')
        self.show()

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        qp.setRenderHint(QPainter.Antialiasing)
        self.drawBezierCurve(qp)
        qp.end()

    def drawBezierCurve(self, qp):

        path = QPainterPath()
        path.moveTo(30, 30)
        path.cubicTo(30, 30, 200, 350, 350, 30)

        qp.drawPath(path)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

本示例绘制了贝塞尔曲线。

path = QPainterPath()
path.moveTo(30, 30)
path.cubicTo(30, 30, 200, 350, 350, 30)

我们使用QPainterPath路径创建贝塞尔曲线。 曲线是通过cubicTo()方法创建的,该方法需要三个点:起点,控制点和终点。

qp.drawPath(path)

使用drawPath()方法绘制最终路径。

Bézier curve

图:贝塞尔曲线

在 PyQt5 教程的这一部分中,我们做了一些基本的绘图。

Ruby Qt 中的布局管理

原文: http://zetcode.com/gui/rubyqt/layoutmanagement/

在 Ruby Qt 编程教程的这一部分中,我们将介绍布局管理器。

在设计应用的 GUI 时,我们决定要使用哪些组件以及如何在应用中组织这些组件。 为了组织我们的组件,我们使用专门的不可见对象,称为布局管理器。 Qt 中有几个选项。 我们可以使用绝对定位,内置布局管理器或创建自定义布局管理器。 我们还可以使用 Qt Designer 直观地构建布局。

Qt 有一些重要的内置布局管理器。 Qt::VBoxLayout类垂直排列小部件。 Qt::HBoxLayout水平排列小部件。 Qt::GridLayout类将小部件布置在网格中。 网格布局是最灵活的布局管理器。 框布局可以相互嵌套以创建复杂的布局。

绝对定位

在大多数情况下,程序员应使用布局管理器。 在某些情况下,我们可以使用绝对定位。 在绝对定位中,程序员以像素为单位指定每个小部件的位置和大小。 如果我们调整窗口大小,则小部件的大小和位置不会改变。 在各种平台上,应用看起来都不同,在 Linux 上看起来不错,在 Mac OS 上看起来不太正常。 在我们的应用中更改字体可能会破坏布局。 如果我们将应用翻译成另一种语言,则必须重做布局。 对于所有这些问题,仅在有理由时才使用绝对定位。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, we lay out widgets
# using absolute positioning.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Absolute"

        init_ui

        resize 300, 280
        move 300, 300

        show
    end

    def init_ui

        setStyleSheet "QWidget { background-color: #414141 }"

        bardejov = Qt::Pixmap.new "bardejov.jpg"
        rotunda = Qt::Pixmap.new "rotunda.jpg"
        mincol = Qt::Pixmap.new "mincol.jpg"

        barLabel = Qt::Label.new self
        barLabel.setPixmap bardejov
        barLabel.move 20, 20

        rotLabel = Qt::Label.new self
        rotLabel.setPixmap rotunda
        rotLabel.move 40, 160

        minLabel = Qt::Label.new self
        minLabel.setPixmap mincol
        minLabel.move 170, 50

    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在此示例中,我们使用绝对定位显示了三幅图像。

barLabel = Qt::Label.new self
barLabel.setPixmap bardejov

Qt::Label小部件用于保存图像。

barLabel.move 20, 20

我们使用move方法将标签放置在窗口上的x = 20y = 20处。

调整窗口大小时,标签将保留其初始大小。

Absolute

图:绝对定位

按钮示例

在下面的示例中,我们将在窗口的右下角放置两个按钮。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, we use box layouts
# to position two buttons in the
# bottom right corner of the window.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Buttons"

        init_ui

        resize 330, 170
        move 300, 300

        show
    end

    def init_ui
        vbox = Qt::VBoxLayout.new self
        hbox = Qt::HBoxLayout.new

        ok = Qt::PushButton.new "OK", self
        apply = Qt::PushButton.new "Apply", self

        hbox.addWidget ok, 1, Qt::AlignRight
        hbox.addWidget apply

        vbox.addStretch 1
        vbox.addLayout hbox
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们使用嵌套框布局来获得我们想要的布局。

vbox = Qt::VBoxLayout.new self
hbox = Qt::HBoxLayout.new

我们使用一个垂直框和一个水平框。

ok = Qt::PushButton.new "OK", self
apply = Qt::PushButton.new "Apply", self

这是两个将进入窗口右下角的按钮。

hbox.addWidget ok, 1, Qt::AlignRight

我们将确定按钮放入水平框中。 第二个参数是stretch因子。 它将扩大分配给“确定”按钮的区域。 它会占用所有可用空间。 该区域内小风口的对齐方式由第三个参数控制。 Qt::AlignRight将按钮向右对齐。

vbox.addStretch 1

这条线创建了一个垂直扩展的白色空间,它将带有按钮的水平框推到底部。

vbox.addLayout hbox

水平框嵌套在垂直框中。

Buttons example

图:按钮示例

Windows 示例

以下是嵌套框布局更复杂的示例。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, use box layouts
# to create a Windows example
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Windows"

        init_ui

        resize 350, 300
        move 300, 300

        show
    end

    def init_ui
        vbox = Qt::VBoxLayout.new self

        vbox1 = Qt::VBoxLayout.new
        hbox1 = Qt::HBoxLayout.new
        hbox2 = Qt::HBoxLayout.new

        windLabel = Qt::Label.new "Windows", self
        edit = Qt::TextEdit.new self
        edit.setEnabled false

        activate = Qt::PushButton.new "Activate", self
        close = Qt::PushButton.new "Close", self
        help = Qt::PushButton.new "Help", self
        ok = Qt::PushButton.new "OK", self

        vbox.addWidget windLabel

        vbox1.addWidget activate
        vbox1.addWidget close, 0, Qt::AlignTop
        hbox1.addWidget edit
        hbox1.addLayout vbox1

        vbox.addLayout hbox1

        hbox2.addWidget help
        hbox2.addStretch 1
        hbox2.addWidget ok

        vbox.addLayout hbox2, 1
        setLayout vbox

    end    
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在此布局中,我们使用两个垂直和水平框。

box = Qt::VBoxLayout.new self

这是示例的基本布局。

windLabel = Qt::Label.new "Windows", self

首先是标签小部件。 它只是转到垂直框的顶部。

vbox1.addWidget activate
vbox1.addWidget close, 0, Qt::AlignTop
hbox1.addWidget edit
hbox1.addLayout vbox1

vbox.addLayout hbox1

在窗口的中心部分,我们有一个文本编辑小部件和两个垂直排列的按钮。 这些按钮进入垂直框。 在此垂直框中,按钮与顶部对齐。 垂直框和文本编辑进入水平框。 该水平框转到标签窗口小部件正下方的基本垂直框。

hbox2.addWidget help
hbox2.addStretch 1
hbox2.addWidget ok

vbox.addLayout hbox2, 1

帮助和确定按钮进入另一个水平框。 这两个按钮之间有一个扩大的空白区域。 同样,水平框转到基本垂直框。

setLayout vbox

基本的垂直框设置为窗口的主要布局。

Windows example

图:窗口示例

新文件夹示例

在最后一个示例中,我们使用Qt::GridLayout管理器创建“新文件夹”布局示例。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, use the GridLayout
# to create a New Folder example.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "New Folder"

        init_ui

        resize 300, 300
        move 300, 300

        show
    end

    def init_ui

        grid = Qt::GridLayout.new self

        nameLabel = Qt::Label.new "Name", self
        nameEdit = Qt::LineEdit.new self
        text = Qt::TextEdit.new self
        okButton = Qt::PushButton.new "OK", self
        closeButton = Qt::PushButton.new "Close", self

        grid.addWidget nameLabel, 0, 0
        grid.addWidget nameEdit, 0, 1, 1, 3
        grid.addWidget text, 1, 0, 2, 4
        grid.setColumnStretch 1, 1
        grid.addWidget okButton, 4, 2
        grid.addWidget closeButton, 4, 3

    end    
end

app = Qt::Application.new(ARGV)
QtApp.new
app.exec

在我们的示例中,我们有一个标签,一行编辑,一个文本编辑和两个按钮。

grid = Qt::GridLayout.new self

我们创建Qt::GridLayout管理器的实例。

grid.addWidget nameLabel, 0, 0

我们将标签小部件放置在网格的第一个单元格中。 单元格从 0 开始计数。最后两个参数是行号和列号。

grid.addWidget nameEdit, 0, 1, 1, 3

线编辑窗口小部件位于第一行第二列。 最后两个参数是行跨度和列跨度。 在水平方向上,小部件将跨越三列。

grid.setColumnStretch 1, 1

该方法的参数是列号和拉伸因子。 在这里,我们将拉伸因子 1 设置到第二列。 这意味着此列将占用所有剩余空间。 之所以这样设置,是因为我们希望按钮保持其初始大小。

New Folder example

图:新文件夹 example

在 Ruby Qt 教程的这一部分中,我们提到了小部件的布局管理。

Ruby Qt 中的小部件

原文: http://zetcode.com/gui/rubyqt/widgets/

在 Ruby Qt 编程教程的这一部分中,我们将介绍基本的小部件。

小部件是 GUI 应用的基本构建块。 多年来,几个小部件已成为所有 OS 平台上所有工具包中的标准。 例如,按钮,复选框或滚动条。 Qt 有一组丰富的小部件,可以满足大多数编程需求。 可以将更多专门的窗口小部件创建为自定义窗口小部件。

Qt::CheckBox

Qt::CheckBox是具有两种状态的窗口小部件:开和关。 接通状态通过复选标记显示。 它用来表示一些布尔属性。 Qt::CheckBox小部件提供一个带有文本标签的复选框。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program uses Qt::CheckBox
# widget to show/hide the title
# of the window.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    slots 'on_toggled(bool)'

    def initialize
        super

        setWindowTitle "Qt::CheckBox"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui
        cb = Qt::CheckBox.new "Show Title", self
        cb.setChecked true
        connect cb, SIGNAL("toggled(bool)"), 
            self, SLOT("on_toggled(bool)")

        cb.move 50, 50

    end

    def on_toggled state
        if state
            setWindowTitle "Qt::CheckBox"
        else
            setWindowTitle ""
        end
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在我们的示例中,我们在窗口上放置了一个复选框。 复选框显示或隐藏窗口的标题。

setWindowTitle "Qt::CheckBox"

在构建窗口期间,我们为窗口设置标题。

cb = Qt::CheckBox.new "Show Title", self

Qt::CheckBox小部件已创建。 构造器的第一个参数是其文本标签。 第二个参数是父窗口小部件。

cb.setChecked true

标题在应用的开始处可见。 因此,也必须选中该复选框。

connect cb, SIGNAL("toggled(bool)"), 
    self, SLOT("on_toggled(bool)")

复选框的状态更改时,会发出toggled信号。 发出信号时,我们触发on_toggled方法。

if state
    setWindowTitle "Qt::CheckBox"
else
    setWindowTitle ""
end

根据复选框的状态,我们显示或隐藏窗口的标题。

Qt::CheckBox

图:Qt::CheckBox

Qt::Label

Qt::Label小部件用于显示文本或图像。 没有用户交互。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program uses Qt::Label widget to 
# show lyrics of a song.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "You know I'm no Good"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui
       text = "Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
You say why did you do it with him today?
and sniff me out like I was Tanqueray\n
cause you're my fella, my guy
hand me your stella and fly
by the time I'm out the door
you tear men down like Roger Moore\n
I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good"

        label = Qt::Label.new text, self
        label.setFont Qt::Font.new "Purisa", 9

        vbox = Qt::VBoxLayout.new
        vbox.addWidget label
        setLayout vbox
    end   
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们的示例在窗口中显示了歌曲的歌词。

       text = "Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
...

我们定义了多行文字。

label = Qt::Label.new text, self
label.setFont Qt::Font.new "Purisa", 9

我们创建标签小部件并更改其字体。

vbox = Qt::VBoxLayout.new
vbox.addWidget label
setLayout vbox

代替手动编码标签的位置和大小,我们将标签放入盒子布局中。

Qt::Label

图:Qt::Label

Qt::LineEdit

Qt::LineEdit是一个小部件,允许输入和编辑单行纯文本。 Qt::LineEdit小部件具有撤消/重做,剪切/粘贴和拖放功能。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program shows text
# which is entered in a Qt::LineEdit
# widget in a Qt::Label widget.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    slots 'on_changed(QString)'

    def initialize
        super

        setWindowTitle "LineEdit"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui

        @label = Qt::Label.new self

        edit = Qt::LineEdit.new self
        connect edit, SIGNAL("textChanged(QString)"),
            self, SLOT("on_changed(QString)")

        edit.move 60, 100
        @label.move 60, 40

    end

    def on_changed text
        @label.setText text
        @label.adjustSize
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在我们的示例中,我们显示了两个小部件。 行编辑和标签小部件。 输入到行编辑中的文本显示在标签窗口小部件中。

edit = Qt::LineEdit.new self

Qt::LineEdit小部件已创建。

connect edit, SIGNAL("textChanged(QString)"),
    self, SLOT("on_changed(QString)")

当我们在行编辑中键入或删除某些文本时,将触发on_changed方法。

def on_changed text
    @label.setText text
    @label.adjustSize
end

on_changed方法中,我们将行编辑的内容设置为标签窗口小部件。 adjustSize方法确保所有文本都是可见的。

Qt::LineEdit widget

图:Qt::LineEdit小部件

ToggleButton

切换按钮是设置了可检查标志的按钮。 切换按钮是具有两种状态的按钮。 已按下但未按下。 通过单击可以在这两种状态之间切换。 在某些情况下此功能非常合适。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program uses toggle buttons to
# change the background colour of
# a widget.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'

class QtApp < Qt::Widget

    slots 'on_clicked()'

    def initialize
        super

        setWindowTitle "Toggle button"

        init_ui

        resize 300, 180
        move 300, 300

        show
    end

    def init_ui

        @color = Qt::Color.new 0, 0, 0

        setGeometry 300, 300, 280, 170
        setWindowTitle "ToggleButton"

        @redb = Qt::PushButton.new 'Red', self
        @redb.setCheckable true
        @redb.move 10, 10

        connect @redb, SIGNAL("clicked()"), SLOT("on_clicked()")

        @greenb = Qt::PushButton.new 'Green', self
        @greenb.setCheckable true
        @greenb.move 10, 60

        connect @greenb, SIGNAL('clicked()'), SLOT("on_clicked()")

        @blueb = Qt::PushButton.new "Blue", self
        @blueb.setCheckable true
        @blueb.move 10, 110

        connect @blueb, SIGNAL("clicked()"), SLOT("on_clicked()")
        @square = Qt::Widget.new self
        @square.setGeometry 150, 20, 100, 100
        @square.setStyleSheet "QWidget { background-color: %s }" % @color.name
    end

    def on_clicked
        red = @color.red
        green = @color.green
        blue = @color.blue

        if @redb.isChecked
            red = 255
        else 
            red = 0
        end

        if @greenb.isChecked
            green = 255
        else 
            green = 0
        end

        if @blueb.isChecked
            blue = 255
        else 
            blue = 0
        end

        @color = Qt::Color.new red, green, blue

        @square.setStyleSheet("QWidget { background-color: %s }" % @color.name) 
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在代码示例中,我们使用三个切换按钮来更改矩形小部件的颜色。

@redb = Qt::PushButton.new 'Red', self
@redb.setCheckable true

我们创建一个Qt::PushButton小部件。 setCheckable方法将按钮更改为切换按钮。

connect @redb, SIGNAL("clicked()"), SLOT("on_clicked()")

我们将按钮插入on_clicked方法调用中。

@square = Qt::Widget.new self
@square.setGeometry 150, 20, 100, 100
@square.setStyleSheet "QWidget { background-color: %s }" % @color.name

我们创建一个方形小部件。 我们设置它的大小。 一开始是黑色的。 在 Qt 中,我们使用样式表来自定义小部件的外观。

on_clicked方法内部,我们确定颜色值并将正方形小部件更新为新颜色。

red = @color.red
green = @color.green
blue = @color.blue

在这里,我们确定方形小部件的当前颜色。

if @redb.isChecked
    red = 255
else 
    red = 0
end

颜色的红色部分根据红色切换按钮的状态而改变。

@color = Qt::Color.new red, green, blue

我们创建一个新的颜色值。

@square.setStyleSheet("QWidget { background-color: %s }" % @color.name) 

正方形的颜色已更新。

Toggle buttons

图:开关按钮

Qt::ComboBox

Qt::ComboBox是一个小部件,允许用户从选项列表中进行选择。 这是一个显示当前项目的选择小部件,可以弹出可选择项目的列表。 组合框可能是可编辑的。 它以占用最少屏幕空间的方式向用户显示选项列表。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program uses the Qt::ComboBox widget.
# The option selected from the combo box is
# displayed in the label widget.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: Sepetmber 2012

require 'Qt'

class QtApp < Qt::Widget

    slots 'on_activated(QString)'

    def initialize
        super

        setWindowTitle "Qt::ComboBox"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui

        @label = Qt::Label.new "Ubuntu", self

        combo = Qt::ComboBox.new self

        combo.addItem "Ubuntu"
        combo.addItem "Fedora"
        combo.addItem "Mandriva"
        combo.addItem "Red Hat"
        combo.addItem "Mint"

        connect combo, SIGNAL("activated(QString)"),
            self, SLOT("on_activated(QString)")

        combo.move 50, 30
        @label.move 50, 100

    end

    def on_activated text
        @label.setText text
        @label.adjustSize
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在我们的代码示例中,我们有两个小部件:组合框和标签小部件。 从组合框中选择的选项显示在标签中。

@label = Qt::Label.new "Ubuntu", self

这是一个标签,它将显示组合框中当前选择的选项。

combo = Qt::ComboBox.new self

我们创建Qt::ComboBox小部件的实例。

combo.addItem "Ubuntu"
combo.addItem "Fedora"
combo.addItem "Mandriva"
combo.addItem "Red Hat"
combo.addItem "Mint"

组合框将填充值。

connect combo, SIGNAL("activated(QString)"),
    self, SLOT("on_activated(QString)")

当我们从组合框中选择一个选项时,将触发on_activated方法。

def on_activated text
    @label.setText text
    @label.adjustSize
end

on_activated方法中,我们将标签小部件更新为从组合框中选择的当前字符串。

Qt::ComboBox widget

图:Qt::ComboBox小部件

在 Ruby Qt 教程的这一部分中,我们介绍了几个 Qt 小部件。

菜单和工具栏

原文: http://zetcode.com/gui/rubyqt/menustoolbars/

在 Ruby Qt 编程教程的这一部分中,我们将使用菜单和工具栏。

菜单栏是 GUI 应用中最可见的部分之一。 它是位于各个菜单中的一组命令。 在控制台应用中,您必须记住所有这些神秘命令,在这里,我们将大多数命令分组为逻辑部分。 有公认的标准可以进一步减少学习新应用的时间。 菜单将我们可以在应用中使用的命令分组。 使用工具栏可以快速访问最常用的命令。

简单菜单

第一个示例将显示一个简单的菜单。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program shows a simple
# menu. It has one action, which
# will terminate the program, when
# selected. 
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: November 2012

require 'Qt'

class QtApp < Qt::MainWindow

    def initialize
        super

        setWindowTitle "Simple menu"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui
        quit = Qt::Action.new "&Quit", self

        file = menuBar().addMenu "&File"
        file.addAction quit

        connect(quit, SIGNAL("triggered()"), 
            Qt::Application.instance, SLOT("quit()"))
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们有一个菜单栏,一个菜单和一个动作。 为了使用菜单,我们必须继承MainWindow小部件。

quit = Qt::Action.new "&Quit", self

此代码行创建一个Action。 每个Menu具有一个或多个动作对象。 注意 AND 字符(&)。 它为以下项目创建快捷方式: Alt + Q 。 它还强调了Q字符。 下拉菜单中的文件时,该快捷方式处于活动状态。

file = menuBar().addMenu "&File"
file.addAction quit

我们创建一个Menu对象。 &字符创建快捷方式: Alt + F 。 连续的快捷键 Alt + FAlt + Q 退出了应用。

connect(quit, SIGNAL("triggered()"), 
    Qt::Application.instance, SLOT("quit()"))

当我们从菜单中选择此选项时,应用退出。

Simple menu

图:简单菜单

子菜单

子菜单是插入另一个菜单对象的菜单。 下一个示例对此进行了演示。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program creates a
# submenu
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: November 2012

require 'Qt'

class QtApp < Qt::MainWindow

    def initialize
        super

        setWindowTitle "Submenu"

        init_ui

        resize 280, 200
        move 300, 300

        show
    end

    def init_ui
        quit = Qt::Action.new "&Quit", self

        file = menuBar().addMenu "&File"
        impm = Qt::Menu.new "Import"

        seeds = Qt::Action.new "Import news feed...", self
        marks = Qt::Action.new "Import bookmarks...", self
        mail = Qt::Action.new "Import mail...", self

        impm.addAction seeds
        impm.addAction marks
        impm.addAction mail

        file.addMenu impm
        file.addAction quit

        connect(quit, SIGNAL("triggered()"), 
            Qt::Application.instance, SLOT("quit()"))
    end    

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在示例中,文件菜单的子菜单中有三个选项。

file = menuBar().addMenu "&File"
impm = Qt::Menu.new "Import"

我们有两个Menu对象。 文件菜单和导入菜单。

seeds = Qt::Action.new "Import news feed...", self
marks = Qt::Action.new "Import bookmarks...", self
mail = Qt::Action.new "Import mail...", self

我们创建三个动作对象。

impm.addAction seeds
impm.addAction marks
impm.addAction mail

我们将动作对象添加到导入菜单中。

file.addMenu impm

最后,我们将导入菜单添加到文件菜单中。

Submenu

图:子菜单

图像,菜单,分隔符

在以下示例中,我们将进一步增强以前的应用。 我们将在菜单中添加图标,使用快捷方式和分隔符。 请注意,默认情况下,可能会将 Gnome 桌面配置为不显示菜单图标。 在这种情况下,我们需要在 Gnome 接口配置中启用menu_have_icons选项。

gconftool-2 --type Boolean --set /desktop/gnome/interface/menus_have_icons True

我们可以使用上面的命令或gconf-editor工具。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program shows image
# menus, shortcuts and a separator
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: November 2012

require 'Qt'

class QtApp < Qt::MainWindow

    def initialize
        super

        setWindowTitle "Image menu"

        init_ui

        resize 280, 200
        move 300, 300

        show
    end

    def init_ui
        newpix = Qt::Icon.new "new.png"
        openpix = Qt::Icon.new "open.png"
        quitpix = Qt::Icon.new "exit.png"

        newa = Qt::Action.new newpix, "&New", self
        open = Qt::Action.new openpix, "&Open", self
        quit = Qt::Action.new quitpix, "&Quit", self
        quit.setShortcut "Ctrl+Q"

        file = menuBar().addMenu "&File"
        file.addAction newa
        file.addAction open
        file.addSeparator
        file.addAction quit

        connect(quit, SIGNAL("triggered()"), 
            Qt::Application.instance, SLOT("quit()"))
    end    

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在我们的示例中,我们有一个包含三个动作的菜单。 如果我们选择退出操作,则实际上只有退出操作才可以执行某些操作。 我们还创建了分隔符和 Ctrl + Q 快捷方式,它们将终止应用。

newpix = Qt::Icon.new "new.png"
openpix = Qt::Icon.new "open.png"
quitpix = Qt::Icon.new "exit.png"

这些是我们将在应用中使用的 PNG 图像。

newa = Qt::Action.new newpix, "&New", self
open = Qt::Action.new openpix, "&Open", self
quit = Qt::Action.new quitpix, "&Quit", self

在这里,我们创建三个动作对象。 第一个参数是Icon

quit.setShortcut "Ctrl+Q"

这行创建一个快捷方式。 通过按下此快捷方式,我们将运行退出操作,这将退出应用。

file.addSeparator

我们创建一个分隔符。 分隔符是一条水平线,它使我们能够将菜单操作分组为一些逻辑部分。

Images, shortcut and a separator

图:图像 s, shortcut and a separator

工具栏

ToolBar类提供了一个可移动面板,其中包含一组控件,这些控件提供对应用操作的快速访问。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program creates a 
# toolbar
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: November 2012

require 'Qt'

class QtApp < Qt::MainWindow

    def initialize
        super

        setWindowTitle "Toolbar"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui
        newpi = Qt::Icon.new "new2.png"
        openpi = Qt::Icon.new "open2.png"
        quitpi = Qt::Icon.new "exit2.png"

        toolbar = addToolBar "main toolbar"
        toolbar.addAction newpi, "New File" 
        toolbar.addAction openpi, "Open File"
        toolbar.addSeparator
        quit = toolbar.addAction quitpi, "Quit Application"

        connect(quit, SIGNAL("triggered()"), 
            Qt::Application.instance, SLOT("quit()"))
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们创建一个带有三个动作对象和一个分隔符的工具栏。

newpi = Qt::Icon.new "new2.png"
openpi = Qt::Icon.new "open2.png"
quitpi = Qt::Icon.new "exit2.png"

工具栏动作对象将显示这些图标。

toolbar = addToolBar "main toolbar"

MainWindowaddToolBar方法为应用创建一个工具栏。 文本字符串为工具栏命名。 此名称用于引用此工具栏,因为一个应用中可以有多个工具栏。 如果右键单击窗口区域,我们将看到一个可检查的选项,该选项显示或隐藏工具栏。

toolbar.addSeparator

我们创建一个垂直分隔符。

connect(quit, SIGNAL("triggered()"), 
    Qt::Application.instance, SLOT("quit()"))

当我们单击退出操作对象时,应用终止。

Toolbar

图:工具栏

撤销重做

以下示例演示了如何停用工具栏上的工具栏按钮。 这是 GUI 编程中的常见做法。 例如,保存按钮。 如果我们将文档的所有更改都保存到磁盘上,则在大多数文本编辑器中,“保存”按钮将被停用。 这样,应用会向用户指示所有更改都已保存。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program disables/enables
#  actions on a toolbar
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: November 2012

require 'Qt'

class QtApp < Qt::MainWindow

    slots 'count()'

    def initialize
        super

        setWindowTitle "Toolbar"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui

        @count = 2

        undoi = Qt::Icon.new "undo.png"
        redoi = Qt::Icon.new "redo.png"
        quitpi = Qt::Icon.new "quit.png"

        toolbar = addToolBar "first toolbar"

        @und = toolbar.addAction undoi, "Undo"
        @red = toolbar.addAction redoi, "Redo"

        connect @und, SIGNAL("triggered()"), self, SLOT("count()")
        connect @red, SIGNAL("triggered()"), self, SLOT("count()")

        toolbar.addSeparator

        quit = toolbar.addAction quitpi, "Quit Application"

        connect quit, SIGNAL("triggered()"), 
            Qt::Application.instance, SLOT("quit()")
    end

    def count

        action = sender

        if "Undo" == action.text
            @count = @count - 1
        else 
            @count = @count + 1
        end

        if @count <= 0
            @und.setDisabled true
            @red.setDisabled false
        end

        if @count >= 5
            @und.setDisabled false
            @red.setDisabled true
        end

    end   
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在我们的示例中,我们有三个Action对象和一个分隔符。 在撤消或重做按钮上单击几下后,它们将被停用。 外观上,按钮显示为灰色。

@count = 2

@count变量确定哪个按钮被激活和禁用。

connect @und, SIGNAL("triggered()"), self, SLOT("count()")
connect @red, SIGNAL("triggered()"), self, SLOT("count()")

单击工具栏按钮,将发射triggered信号。 我们将此信号连接到count方法。

action = sender

工具栏上的两个按钮都调用count方法。 我们需要在它们之间说出来。 这条线确定哪个动作对象实际发出信号。

if "Undo" == action.text
    @count = @count - 1
else 
    @count = @count + 1
end

撤消工具栏按钮从计数变量中减去 1。 重做添加 1.根据计数变量的值,我们启用或禁用工具栏按钮。

if @count <= 0
    @und.setDisabled true
    @red.setDisabled false
end

setDisabled方法激活或停用工具栏按钮。

Undo redo

图:撤销和重做

在 Ruby Qt 教程的这一部分中,我们提到了菜单和工具栏。

Ruby Qt 中的对话框

原文: http://zetcode.com/gui/rubyqt/dialogs/

在 Ruby Qt 编程教程的这一部分中,我们将使用对话框。

对话框窗口或对话框是大多数现代 GUI 应用必不可少的部分。 对话被定义为两个或更多人之间的对话。 在计算机应用中,对话框是一个窗口,用于与应用“对话”。 对话框用于输入数据,修改数据,更改应用设置等。对话框是用户与计算机程序之间进行通信的重要手段。

MessageDialog

消息框是方便的对话框,可向应用的用户提供消息。 该消息由文本和图像数据组成。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program demonstrates
# MessageBox dialogs
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: July 2009

require 'Qt'

class QtApp < Qt::Widget

    slots 'showDialog()'

    def initialize
        super

        setWindowTitle "Message dialogs"

        init_ui

        resize 250, 150
        move 300, 300

        show
    end

    def init_ui

        grid = Qt::GridLayout.new self
        grid.setSpacing 2

        error = Qt::PushButton.new "Error", self
        warning = Qt::PushButton.new "Warning", self
        question = Qt::PushButton.new "Question", self
        information = Qt::PushButton.new "Information", self
        about = Qt::PushButton.new "About", self

        grid.addWidget error, 0, 0
        grid.addWidget warning, 0, 1
        grid.addWidget question, 1, 0
        grid.addWidget information, 1, 1
        grid.addWidget about, 2, 0

        connect(error, SIGNAL("clicked()"),
            self, SLOT("showDialog()"))

        connect(warning, SIGNAL("clicked()"),
            self, SLOT("showDialog()"))

        connect(question, SIGNAL("clicked()"),
            self, SLOT("showDialog()"))

        connect(information, SIGNAL("clicked()"),
            self, SLOT("showDialog()"))

        connect(about, SIGNAL("clicked()"),
            self, SLOT("showDialog()"))

    end   

    def showDialog

        button = sender

        if "Error" == button.text
            Qt::MessageBox.critical self, "Error", "Error loading file!"
        elsif "Warning" == button.text
            Qt::MessageBox.warning self, "Warning", "Operation not permitted!"
        elsif "Question" == button.text
            Qt::MessageBox.question self, "Question", "Are you sure to quit?"
        elsif "Information" == button.text
            Qt::MessageBox.information self, "Information", "Download completed."
        elsif "About" == button.text
            Qt::MessageBox.about self, "About", "ZetCode Ruby Qt tutorial."
        end
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们使用GridLayout管理器来设置五个按钮的网格。 每个按钮显示一个不同的消息框。

if "Error" == button.text
    Qt::MessageBox.critical self, "Error", "Error loading file!"

如果按下错误按钮,则会显示错误对话框。 我们使用MessageBox类的静态方法来显示消息框。

Information message dialog

图:信息对话框

Qt::InputDialog

Qt::InputDialog类提供了一个简单的便捷对话框,可从用户那里获取单个值。 输入值可以是字符串,数字或列表中的项目。 必须设置标签以告知用户他们应该输入什么。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program shows an input
# dialog
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: July 2009

require 'Qt'

class QtApp < Qt::Widget

    slots 'showDialog()'

    def initialize
        super

        setWindowTitle "Input dialog"

        init_ui

        resize 400, 80
        move 300, 300

        show
    end

    def init_ui

        show = Qt::PushButton.new "Dialog", self

        connect(show, SIGNAL("clicked()"),
            self, SLOT("showDialog()"))

        show.move 20, 20

        @edit = Qt::LineEdit.new self
        @edit.move 130, 22

    end   

    def showDialog

        text = Qt::InputDialog.getText self, "Input Dialog",
            "Enter your name"

        if text != nil 
            name = text.strip
            if not name.empty?
                @edit.setText name
            end
        end
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在代码示例中,我们有一个按钮和一行编辑。 该按钮显示一个输入对话框。 我们得到一些文本,文本显示在行编辑小部件中。

text = Qt::InputDialog.getText self, "Input Dialog",
    "Enter your name"

getText静态方法创建输入对话框。 对话框中的文本存储在text变量中。

if text != nil 
    name = text.strip
    if not name.empty?
        @edit.setText name
    end
end

在更新行编辑之前,请确保text变量不为null且不为空,并且不仅由空格组成。

Input dialog

图:输入对话框

Qt::ColorDialog

Qt::ColorDialog类提供一个用于指定颜色的对话框小部件。 颜色对话框的功能是允许用户选择颜色。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, we use the
# ColorDialog to change the color
# of a label text
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: July 2009

require 'Qt'

class QtApp < Qt::Widget

    slots 'showDialog()'

    def initialize
        super

        setWindowTitle "Color dialog"

        init_ui

        resize 400, 300
        move 300, 300

        show
    end

    def init_ui

        @label = Qt::Label.new "ZetCode Ruby Qt tutorial", self

        vbox = Qt::VBoxLayout.new self
        @label.setAlignment Qt::AlignCenter
        vbox.addWidget @label

    end   

    def mousePressEvent event

        color = Qt::ColorDialog.getColor

        if not color.isValid
            return
        end

        @label.setStyleSheet "QWidget { color: %s }" % color.name
    end

end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们在窗口中心显示一些文本。 通过单击窗口区域,我们显示一个颜色对话框。 我们将文本前景色更改为从对话框中选择的颜色。

def mousePressEvent event
    ...
end

为了接收我们窗口的鼠标按下事件,我们必须重新实现mousePressEvent方法。

color = Qt::ColorDialog.getColor

正在创建ColorDialog。 所选颜色存储在color变量中。

@label.setStyleSheet "QWidget { color: %s }" % color.name

在这里,我们更新标签文本的前景色。

ColorDialog

图:Qt::ColorDialog

Qt::FontDialog

Qt::FontDialog类提供用于选择字体的对话框小部件。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, we use the
# FontDialog to change the font
# of a label text
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: July 2009

require 'Qt'

class QtApp < Qt::Widget

    slots 'showDialog()'

    def initialize
        super

        setWindowTitle "Font dialog"

        init_ui

        resize 400, 300
        move 300, 300

        show
    end

    def init_ui

        @label = Qt::Label.new "ZetCode Ruby Qt tutorial", self

        vbox = Qt::VBoxLayout.new self
        @label.setAlignment Qt::AlignCenter
        vbox.addWidget @label

    end   

    def mousePressEvent event

        ok = Qt::Boolean.new
        font = Qt::FontDialog.getFont ok

        if not ok 
            return
        end

        @label.setFont font
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

此示例与上一个示例相似。 这次,我们更改文本的字体。

font = Qt::FontDialog.getFont ok

正在创建Qt::FontDialog

if not ok 
    return
end

如果单击对话框的“确定”按钮,则布尔值ok变量为true。 如果按下了取消按钮,我们将从方法中返回。

@label.setFont font

我们将标签更新为新选择的字体。

FontDialog

图:Qt::FontDialog

在 Ruby Qt 教程的这一部分中,我们使用了对话框窗口。

用 Ruby Qt 绘图

原文: http://zetcode.com/gui/rubyqt/painting/

在 Ruby Qt 编程教程的这一部分中,我们将进行绘图。

我们什么时候需要油漆? 在某些情况下,当我们需要从头开始创建小部件时。 在这种情况下,我们需要绘图。 或者我们想创建图表,特殊装饰,效果或小部件增强。

当我们在 Qt 库中进行绘图时,Painter类将发挥作用。 绘图事件通过paintEvent方法接收。 若要进行自定义绘图,我们必须重新实现此方法。

图案

在 Qt 中,我们可以使用各种图案来填充形状的内部。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program draws nine rectangles.
# The interiors are filled with
# different built-in patterns.
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Patterns"

        resize 350, 280
        move 300, 300

        show
    end

    def paintEvent event

        painter = Qt::Painter.new self

        drawPatterns painter
        painter.end
    end

    def drawPatterns painter

        painter.setPen Qt::NoPen

        painter.setBrush Qt::HorPattern
        painter.drawRect 10, 15, 90, 60

        painter.setBrush Qt::VerPattern
        painter.drawRect 130, 15, 90, 60

        painter.setBrush Qt::CrossPattern
        painter.drawRect 250, 15, 90, 60

        painter.setBrush Qt::Dense7Pattern
        painter.drawRect 10, 105, 90, 60

        painter.setBrush Qt::Dense6Pattern
        painter.drawRect 130, 105, 90, 60

        painter.setBrush Qt::Dense5Pattern
        painter.drawRect 250, 105, 90, 60

        painter.setBrush Qt::BDiagPattern
        painter.drawRect 10, 195, 90, 60

        painter.setBrush Qt::FDiagPattern
        painter.drawRect 130, 195, 90, 60

        painter.setBrush Qt::DiagCrossPattern
        painter.drawRect 250, 195, 90, 60
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在代码示例中,我们将绘制九个矩形,并用不同的画笔图案填充它们。

def paintEvent event

    painter = Qt::Painter.new self

    drawPatterns painter
    painter.end
end

当需要重绘窗口区域时,将调用paintEvent方法。 当我们调整窗口大小,最大化或最小化窗口时,就会发生这种情况。在此方法中,我们创建了Painter对象。 该对象用于在 Qt 中进行所有绘制。 绘图本身被委托给drawPatterns方法。

painter.setPen Qt::NoPen

笔对象用于绘制形状的轮廓。 在我们的示例中,我们将不使用笔。

painter.setBrush Qt::HorPattern

我们将水平图案设置为画笔。

painter.drawRect 10, 15, 90, 60

我们用当前的笔和画笔绘制一个矩形。 该方法的前两个参数是 x,y 坐标。 最后两个参数是矩形的宽度和高度。

painter.end

end方法完成绘制。 释放绘图时使用的所有资源。

Patterns

图:图案

形状

Qt 绘图 API 可以绘制各种形状。 以下编程代码示例将显示其中的一些。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program draws basic shapes
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Basic shapes"

        resize 350, 280
        move 300, 300

        show
    end

    def paintEvent event

          painter = Qt::Painter.new self

          drawShapes painter
          painter.end
    end

    def drawShapes painter

        painter.setRenderHint Qt::Painter::Antialiasing
        painter.setPen Qt::Color.new 150, 150, 150
        painter.setBrush Qt::Brush.new Qt::Color.new 150, 150, 150

        path1 = Qt::PainterPath.new

        path1.moveTo 5, 5
        path1.cubicTo 40, 5,  50, 50,  99, 99
        path1.cubicTo 5, 99,  50, 50,  5, 5
        painter.drawPath path1

        painter.drawPie 130, 20, 90, 60, 30*16, 120*16
        painter.drawChord 240, 30, 90, 60, 0, 16*180
        painter.drawRoundRect 20, 120, 80, 50

        points = []
        points.push  Qt::Point.new 130, 140
        points.push  Qt::Point.new 180, 170
        points.push  Qt::Point.new 180, 140
        points.push  Qt::Point.new 220, 110
        points.push  Qt::Point.new 140, 100

        polygon = Qt::Polygon.new points

        painter.drawPolygon polygon
        painter.drawRect 250, 110, 60, 60

        baseline = Qt::PointF.new 20, 250
        font = Qt::Font.new "Georgia", 55
        path2 = Qt::PainterPath.new
        path2.addText baseline, font, "Q"
        painter.drawPath path2

        painter.drawEllipse 140, 200, 60, 60
        painter.drawEllipse 240, 200, 90, 60

    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在此代码示例中,我们在窗口上绘制了九种不同的形状。 复杂路径,饼图,和弦,圆角矩形,多边形,矩形,基于字符的形状,圆形和椭圆形。

painter.setRenderHint Qt::Painter::Antialiasing

我们在示例中使用抗锯齿。 抗锯齿形状看起来更好,但是绘制它们需要更多时间。

painter.setPen Qt::Color.new 150, 150, 150
painter.setBrush Qt::Brush.new Qt::Color.new 150, 150, 150

我们使用深灰色的笔和画笔绘制形状。

path1 = Qt::PainterPath.new

path1.moveTo 5, 5
path1.cubicTo 40, 5,  50, 50,  99, 99
path1.cubicTo 5, 99,  50, 50,  5, 5
painter.drawPath path1

使用PainterPath对象创建第一个复杂形状。 PainterPath类为绘图操作提供了一个容器。 画家路径是由许多图形构造块(例如矩形,椭圆形,直线和曲线)组成的对象。

painter.drawPie 130, 20, 90, 60, 30*16, 120*16
painter.drawChord 240, 30, 90, 60, 0, 16*180
painter.drawRoundRect 20, 120, 80, 50

这三条线绘制了一个饼图,一个和弦和一个圆角矩形。

points = []
points.push  Qt::Point.new 130, 140
points.push  Qt::Point.new 180, 170
points.push  Qt::Point.new 180, 140
points.push  Qt::Point.new 220, 110
points.push  Qt::Point.new 140, 100

polygon = Qt::Polygon.new points

painter.drawPolygon polygon

我们使用五个点的数组来创建多边形。

baseline = Qt::PointF.new 20, 250
font = Qt::Font.new "Georgia", 55
path2 = Qt::PainterPath.new
path2.addText baseline, font, "Q"
painter.drawPath path2

这些线创建基于字符的形状。

painter.drawEllipse 140, 200, 60, 60
painter.drawEllipse 240, 200, 90, 60

这两条线分别创建一个圆和一个椭圆。

Shapes

图:形状

透明矩形

透明度是能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。

在计算机图形学中,我们可以使用 alpha 合成实现透明效果。 Alpha 合成是将图像与背景组合以创建部分透明外观的过程。 合成过程使用 Alpha 通道。 (wikipedia.org,answers.com)

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program draws ten
# rectangles with different
# levels of transparency.
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Transparent rectangles"

        resize 590, 90
        move 300, 300

        show
    end

    def paintEvent event

          painter = Qt::Painter.new self

          drawRectangles painter
          painter.end
    end

    def drawRectangles painter

        painter.setPen Qt::NoPen

        for i in 1..10
            painter.setBrush Qt::Brush.new Qt::Color.new 0, 0, 255, i*25
            painter.drawRect 50*i, 20, 40, 40
        end

    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在示例中,我们将绘制十个具有不同透明度级别的矩形。

painter.setPen Qt::NoPen

我们不用笔。

for i in 1..10
    painter.setBrush Qt::Brush.new Qt::Color.new 0, 0, 255, i*25
    painter.drawRect 50*i, 20, 40, 40
end

Color对象的最后一个参数是 alpha 透明度值。

Transparent rectangles

图:透明矩形

甜甜圈形状

在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program draws a donut
# shape
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Donut"

        resize 350, 280
        move 300, 300

        show
    end

    def paintEvent event

          painter = Qt::Painter.new self

          drawDonut painter
          painter.end
    end

    def drawDonut painter

        painter.setRenderHint Qt::Painter::Antialiasing

        color = Qt::Color.new
        color.setNamedColor "#333333"

        pen = Qt::Pen.new color
        pen.setWidth 1
        painter.setPen pen

        w = width
        h = height

        painter.translate Qt::Point.new w/2, h/2

        72.times do
            painter.drawEllipse -125, -40, 250, 80
            painter.rotate 5.0
        end
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在此示例中,我们创建一个甜甜圈。 形状类似于曲奇,因此得名“甜甜圈”。

color = Qt::Color.new
color.setNamedColor "#333333"

我们可以使用十六进制表示法来创建颜色对象。

w = width
h = height

在这里,我们确定窗口的宽度和高度。

painter.translate Qt::Point.new w/2, h/2

我们将坐标系移到窗口的中间。 这样,我们使绘图在数学上更容易。

72.times do
    painter.drawEllipse -125, -40, 250, 80
    painter.rotate 5.0
end

我们绘制一个椭圆对象 72 次。 每次,我们将椭圆旋转 5 度。 这将创建我们的甜甜圈形状。

Donut

图:多纳圈

绘制文字

在最后一个示例中,我们将在窗口上绘制文本。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# This program draws text
# on the window
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require 'Qt'

class QtApp < Qt::Widget

    def initialize
        super

        setWindowTitle "Soulmate"

        resize 370, 240
        move 300, 300

        show
    end

    def paintEvent event

          painter = Qt::Painter.new self

          drawText painter
          painter.end
    end

    def drawText painter

        painter.setBrush Qt::Brush.new Qt::Color.new 25, 25, 25
        painter.setFont Qt::Font.new "Purisa", 10

        painter.drawText Qt::Point.new(20, 30),
                "Most relationships seem so transitory"
        painter.drawText Qt::Point.new(20, 60),
                "They're good but not the permanent one"
        painter.drawText Qt::Point.new(20, 120),
                "Who doesn't long for someone to hold"
        painter.drawText Qt::Point.new(20, 150),
                "Who knows how to love without being told"
        painter.drawText Qt::Point.new(20, 180),
                "Somebody tell me why I'm on my own"
        painter.drawText Qt::Point.new(20, 210),
                "If there's a soulmate for everyone"

    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

我们在窗口上画一首歌歌词。

painter.setFont Qt::Font.new "Purisa", 10

我们为文本设置了 Purisa 字体。

painter.drawText Qt::Point.new(20, 30),
        "Most relationships seem so transitory"

drawText方法用于绘制文本。

Drawing text

图:绘制文本

在 Ruby Qt 编程教程的这一部分中,我们做了一些绘图。

Ruby Qt 中的自定义小部件

原文: http://zetcode.com/gui/rubyqt/customwidget/

在 Ruby Qt 编程教程的这一部分中,我们将创建一个自定义窗口小部件。

工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 程序员必须自己创建此类小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。

刻录小部件

在下一个示例中,我们将创建一个自定义刻录小部件。 可以在 Nero 或 K3B 之类的应用中看到此小部件。 该小部件将从头开始创建。

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial

# In this program, we create
# a custom widget
#
# @author jan bodnar
# website zetcode.com
# last modified July 2009

require 'Qt'

PANEL_HEIGHT = 30
DISTANCE = 19
LINE_WIDTH = 5
DIVISIONS = 10
FULL_CAPACITY = 700
MAX_CAPACITY = 750

class Burning < Qt::Widget 

    def initialize(parent) 
        super(parent)

        @num = [ "75", "150", "225", "300", 
            "375", "450", "525", "600", "675" ]

        @redColor = Qt::Color.new 255, 175, 175
        @yellowColor = Qt::Color.new 255, 255, 184

        @parent = parent
        setMinimumHeight PANEL_HEIGHT
    end

    def paintEvent event

        painter = Qt::Painter.new self

        drawWidget painter
        painter.end
    end

    def drawWidget painter

        w = width.to_f

        slid_width = @parent.getCurrentWidth

        step = (w / DIVISIONS).round.to_f

        till = ((w / MAX_CAPACITY) * slid_width).to_f
        full = ((w / MAX_CAPACITY) * FULL_CAPACITY).to_f

        if slid_width > FULL_CAPACITY
            painter.setPen @yellowColor
            painter.setBrush Qt::Brush.new @yellowColor
            painter.drawRect Qt::RectF.new 0, 0, full, PANEL_HEIGHT
            painter.setPen @redColor
            painter.setBrush Qt::Brush.new @redColor
            painter.drawRect Qt::RectF.new full+1, 0, till-full, PANEL_HEIGHT
        else 
            if slid_width > 0
               painter.setPen @yellowColor
               painter.setBrush Qt::Brush.new @yellowColor
               painter.drawRect Qt::RectF.new 0, 0, till, PANEL_HEIGHT
            end
        end

        painter.setPen Qt::Color.new 90, 90, 90
        painter.setBrush Qt::NoBrush
        painter.drawRect 0, 0, w-1, PANEL_HEIGHT-1

        newFont = font
        newFont.setPointSize 7
        painter.setFont newFont

        for i in (1..@num.length)
            painter.drawLine Qt::LineF.new i*step, 1, i*step, LINE_WIDTH

            metrics = Qt::FontMetrics.new newFont

            w = metrics.width @num[i-1]
            painter.drawText(Qt::PointF.new(i*step-w/2, DISTANCE), @num[i-1])

        end
    end
end

class QtApp < Qt::Widget 

    slots 'onChanged(int)'

    def initialize
        super
        setWindowTitle "The Burning Widget"

        initUI

        resize 370, 200
        move 300, 300
        show
    end

    def initUI

       @cur_width = 0

       @slider = Qt::Slider.new Qt::Horizontal , self
       @slider.setMaximum MAX_CAPACITY
       @slider.setGeometry 50, 50, 130, 30 

       connect(@slider, SIGNAL("valueChanged(int)"), self, SLOT("onChanged(int)"))

       vbox = Qt::VBoxLayout.new self
       hbox = Qt::HBoxLayout.new

       vbox.addStretch 1

       @widget = Burning.new self
       hbox.addWidget @widget, 0

       vbox.addLayout hbox

       setLayout vbox
    end

    def onChanged val
        @cur_width = val
        @widget.repaint
    end

    def getCurrentWidth
      return @cur_width
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

在这个文件中,我们创建了刻录小部件。

class Burning < Qt::Widget 

自定义窗口小部件基于Widget小部件。

PANEL_HEIGHT = 30
DISTANCE = 19
LINE_WIDTH = 5
DIVISIONS = 10
FULL_CAPACITY = 700
MAX_CAPACITY = 750

这些是重要的常数。 PANEL_HEIGHT定义自定义窗口小部件的高度。 DISTANCE是比例尺上的数字与其父边框顶部之间的距离。 LINE_WIDTH是垂直线的宽度。 DIVISIONS是秤的数量。 FULL_CAPACITY是媒体的最大容量。 达到目标后,就会发生过度刻录。 这通过红色可视化。 MAX_CAPACITY是介质的最大容量。

@num = [ "75", "150", "225", "300", 
    "375", "450", "525", "600", "675" ]

我们使用这些数字来构建Burning小部件的比例。

def paintEvent event

    painter = Qt::Painter.new self

    drawWidget painter
    painter.end
end

自定义窗口小部件的图形委托给drawWidget方法。

slid_width = @parent.getCurrentWidth

我们使用它来获取当前选定的滑块值。

w = width.to_f

我们得到小部件的宽度。 自定义窗口小部件的宽度是动态的。 用户可以调整大小。

till = ((w / MAX_CAPACITY) * slid_width).to_f
full = ((w / MAX_CAPACITY) * FULL_CAPACITY).to_f

我们使用w变量进行转换。 在比例尺值和自定义小部件的度量之间。 请注意,我们使用浮点值。 我们在绘图中获得了更高的精度。

painter.setPen @redColor
painter.setBrush Qt::Brush.new @redColor
painter.drawRect Qt::RectF.new full+1, 0, till-full, PANEL_HEIGHT

这三行画出红色矩形,表示过度燃烧。

painter.drawRect 0, 0, w-1, PANEL_HEIGHT-1

这是小部件的外围,即外部矩形。

painter.drawLine Qt::LineF.new i*step, 1, i*step, LINE_WIDTH

在这里,我们画出小的垂直线。

w = metrics.width @num[i-1]
painter.drawText(Qt::PointF.new(i*step-w/2, DISTANCE), @num[i-1])

在这里,我们绘制刻度的数字。 为了精确定位数字,我们必须获得字符串的宽度。

@widget = Burning.new self
hbox.addWidget @widget, 0

我们创建Burning小部件的实例并将其添加到水平框中。

def onChanged val
    @cur_width = val
    @widget.repaint
end

当滑块的值更改时,我们将其存储在@cur_width变量中,然后重新绘制自定义窗口小部件。

def getCurrentWidth
return @cur_width
end

定制小部件调用此方法以获取实际的滑块值。

The Burning widget

图:刻录小部件

在 Ruby Qt 教程的这一部分中,我们已经演示了如何创建自定义窗口小部件。

Ruby Qt 中的贪食蛇

原文: http://zetcode.com/gui/rubyqt/nibbles/

在 Ruby Qt 编程教程的这一部分中,我们将创建一个贪食蛇游戏克隆。

贪食蛇是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。

开发

蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 游戏结束后,我们在窗口中心显示"Game Over"消息。

Board.rb

WIDTH = 300
HEIGHT = 300
DOT_SIZE = 10
ALL_DOTS = WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE)
RAND_POS = 29
DELAY = 140

$x = [0] * ALL_DOTS
$y = [0] * ALL_DOTS

class Board < Qt::Widget

    def initialize(parent)
        super(parent)

        setFocusPolicy Qt::StrongFocus

        initGame
    end

    def initGame

        @left = false
        @right = true
        @up = false
        @down = false
        @inGame = true
        @dots = 3

        begin
            @ball = Qt::Image.new "dot.png"
            @apple = Qt::Image.new "apple.png"
            @head = Qt::Image.new "head.png"
        rescue
            puts "cannot load images"
        end

        for i in (0..@dots)
            $x[i] = 50 - i * 10
            $y[i] = 50
        end

        locateApple
        setStyleSheet "QWidget { background-color: #000000 }"

        @timer = Qt::BasicTimer.new 
        @timer.start(140, self)

    end

    def paintEvent event

        painter = Qt::Painter.new
        painter.begin self

        if @inGame
            drawObjects painter
        else 
            gameOver painter
        end

        painter.end
    end

    def drawObjects painter

        painter.drawImage @apple_x, @apple_y, @apple

        for z in (0..@dots)
            if z == 0
                painter.drawImage $x[z], $y[z], @head
            else 
                painter.drawImage $x[z], $y[z], @ball
            end
        end
    end

    def gameOver painter
        msg = "Game Over"
        small = Qt::Font.new "Helvetica", 12,
            Qt::Font::Bold.value

        metr = Qt::FontMetrics.new small

        textWidth = metr.width msg
        h = height
        w = width

        painter.setPen Qt::Color.new Qt::white
        painter.setFont small
        painter.translate Qt::Point.new w/2, h/2
        painter.drawText -textWidth/2, 0, msg
    end

    def checkApple

        if $x[0] == @apple_x and $y[0] == @apple_y 
            @dots = @dots + 1
            locateApple
        end
    end

    def move

        z = @dots

        while z > 0
            $x[z] = $x[(z - 1)]
            $y[z] = $y[(z - 1)]
            z = z - 1
        end

        if @left
            $x[0] -= DOT_SIZE
        end

        if @right 
            $x[0] += DOT_SIZE
        end

        if @up
            $y[0] -= DOT_SIZE
        end

        if @down
            $y[0] += DOT_SIZE
        end

     end

    def checkCollision

        z = @dots

        while z > 0
            if z > 4 and $x[0] == $x[z] and $y[0] == $y[z]
                @inGame = false
            end
            z = z - 1
        end

        if $y[0] > HEIGHT
            @inGame = false
        end

        if $y[0] < 0
            @inGame = false
        end

        if $x[0] > WIDTH
            @inGame = false
        end

        if $x[0] < 0
            @inGame = false
        end    

    end

    def locateApple

        r = rand RAND_POS
        @apple_x = r * DOT_SIZE
        r = rand RAND_POS
        @apple_y = r * DOT_SIZE
    end

    def timerEvent event

        if @inGame 
            checkApple
            checkCollision
            move
        else 
            @timer.stop
        end

        repaint
    end

    def keyPressEvent event

        key = event.key

        if key == Qt::Key_Left.value and not @right
            @left = true
            @up = false
            @down = false
        end

        if key == Qt::Key_Right.value and not @left
            @right = true
            @up = false
            @down = false
        end

        if key == Qt::Key_Up.value and not @down
            @up = true
            @right = false
            @left = false            
        end

        if key == Qt::Key_Down.value and not @up
            @down = true
            @right = false
            @left = false
        end
    end
end

首先,我们将定义一些在游戏中使用的常量。

WIDTHHEIGHT常数确定电路板的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义了板上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。

$x = [0] * ALL_DOTS
$y = [0] * ALL_DOTS

这两个数组存储蛇的所有可能关节的 x,y 坐标。

initGame方法初始化变量,加载图像并启动超时功能。

if @inGame
    drawObjects painter
else 
    gameOver painter
end

paintEvent方法内部,我们检查@inGame变量。 如果为真,则绘制对象。 苹果和蛇的关节。 否则,我们显示"Game Over"文本。

def drawObjects painter

    painter.drawImage @apple_x, @apple_y, @apple

    for z in (0..@dots)
        if z == 0
            painter.drawImage $x[z], $y[z], @head
        else 
            painter.drawImage $x[z], $y[z], @ball
        end
    end
end

drawObjects方法绘制苹果和蛇的关节。 蛇的第一个关节是其头部,用红色圆圈表示。

def checkApple

    if $x[0] == @apple_x and $y[0] == @apple_y 
        @dots = @dots + 1
        locateApple
    end
end

checkApple方法检查蛇是否击中了苹果对象。 如果是这样,我们添加另一个蛇形关节并调用locateApple方法,该方法将随机放置一个新的Apple对象。

move方法中,我们有游戏的关键算法。 要了解它,请看一下蛇是如何运动的。 您控制蛇的头。 您可以使用光标键更改其方向。 其余关节在链上向上移动一个位置。 第二关节移动到第一个关节的位置,第三关节移动到第二个关节的位置,依此类推。

while z > 0
    $x[z] = $x[(z - 1)]
    $y[z] = $y[(z - 1)]
    z = z - 1
end

该代码将关节向上移动。

if @left
    $x[0] -= DOT_SIZE
end

将头向左移动。

checkCollision方法中,我们确定蛇是否击中了自己或撞墙之一。

while z > 0
    if z > 4 and $x[0] == $x[z] and $y[0] == $y[z]
        @inGame = false
    end
    z = z - 1
end

如果蛇用头撞到关节之一,我们就结束游戏。

if $y[0] > HEIGHT
    @inGame = false
end

如果蛇击中了棋盘的底部,我们就结束了游戏。

locateApple方法在板上随机放置一个苹果。

r = rand RAND_POS

我们得到一个从 0 到RAND_POS-1的随机数。

@apple_x = r * DOT_SIZE
...
@apple_y = r * DOT_SIZE

这些行设置了apple对象的 x 和 y 坐标。

if @inGame 
    checkApple
    checkCollision
    move
else 
    @timer.stop
end

每 140 毫秒,将调用timerEvent方法。 如果我们参与了游戏,我们将调用三种构建游戏逻辑的方法。 否则,我们将停止计时器。

Board类的keyPressEvent方法中,我们确定按下的键。

if key == Qt::Key_Left.value and not @right
    @left = true
    @up = false
    @down = false
end

如果单击左光标键,则将@left变量设置为true。 在move方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。

Nibbles.rb

#!/usr/bin/ruby

# ZetCode Ruby Qt tutorial
#
# In this program, we create
# a Nibbles game clone.
#
# author: Jan Bodnar
# website: www.zetcode.com
# last modified: September 2012

require 'Qt'
require 'Board'

class QtApp < Qt::MainWindow

    def initialize
        super

        setWindowTitle "Nibbles"

        setCentralWidget Board.new(self)

        resize 310, 310
        move 300, 300

        show
    end
end

app = Qt::Application.new ARGV
QtApp.new
app.exec

Nibbles.rb文件中,我们设置了贪食蛇游戏。

Nibbles

图:贪食蛇

这是使用 Qt 库和 Ruby 编程语言编程的贪食蛇电脑游戏。

Visual Basic Qyoto 教程

原文: http://zetcode.com/gui/vbqyoto/

这是 Visual Basic Qyoto 教程。 在本教程中,您将学习在 Visual Basic 中使用 Qyoto 构建 GUI 的基础知识。 本教程适合初学者和中级程序员。

目录

Qyoto

Qyoto 是一个库,它提供 Qt 库与 .NET 语言(如 C# 或 Visual Basic)的绑定。 Qt 是功能强大的跨平台应用开发框架。 它的母语是 C++ 。 Qyoto 是 KDE 桌面环境的一部分。

Visual Basic

Visual Basic 是.NET Framework 的高级编程语言。 这是一种非常流行的语言。 目前,它是世界十大流行语言之一。 它是为 Windows 平台创建的。 Mono 项目已为 Linux 和 Mac 平台创建了一个克隆。

相关教程

我们在 ZetCode 上有完整的 Visual Basic 教程。 其他 GUI 工具包的 Visual Basic 教程包括 Visual Basic GTK# 教程Visual Basic Winforms 教程。 另外,还有一个针对 C# 语言的 Qyoto 教程: Qyoto C# 教程

Qyoto 介绍

原文: http://zetcode.com/gui/vbqyoto/introduction/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将介绍 Qyoto 库并使用 Visual Basic 编程语言创建第一个 Qyoto 程序。

本教程的目的是帮助您开始使用 Qyoto 和 Visual Basic。 可以在此处下载本教程中使用的图像。 我使用了 Gnome 项目的探戈图标包中的一些图标。

关于

Qyoto是一个库,提供 Qt 库与.NET 语言(如 C# 或 Visual Basic)的绑定。 Qt 是功能强大的跨平台应用开发框架。 它的母语是 C++ 。 Qyoto 是 KDE 桌面环境的一部分。

vbnc -r:/usr/lib/cli/qyoto-4.3/qt-dotnet.dll quitbutton.vb

上面的命令显示了如何编译quitbutton示例。 mono VB 编译器的-r参数加载 Qt 程序集。 这是一个动态库。 该命令显示了 Ubuntu 系统上 dll 库的路径。

创建工具提示

第一个示例将显示一个工具提示。 工具提示是一个小的矩形窗口,它提供有关对象的简短信息。 它通常是一个 GUI 组件。 它是应用帮助系统的一部分。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program displays
' a tooltip
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.InitUI()

    End Sub

    Private Sub InitUI()

        Me.Tooltip = "This is QWidget"

        Me.SetWindowTitle("Tooltip")
        Me.Resize(250, 150)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

该示例创建一个窗口。 如果将鼠标指针悬停在窗口区域上方,则会弹出一个工具提示。

Imports Qyoto

Imports关键字导入我们将在应用中使用的必要类型。

Public Class VBQApp 
    Inherits QWidget

该示例继承自QWidget。 QWidget 类是所有用户界面对象的基类。 小部件是用户界面的原子。 它从窗口系统接收鼠标,键盘和其他事件。

Me.SetWindowTitle("Tooltip")

此方法调用为窗口创建标题。

Me.Tooltip = "This is QWidget"

我们通过ToolTip属性设置工具提示。

Me.Resize(250, 150)

在这里,我们设置窗口的宽度和高度。

Me.Move(300, 300)

Move()方法在屏幕上移动窗口。

Me.Show()

一切准备就绪后,我们在屏幕上显示窗口。

Dim qapp As New QApplication(args)
Dim app As New VBQApp
QApplication.Exec()

这三行设置了应用。

Tooltip

图:工具提示

使窗口居中

在第二个示例中,我们将窗口置于屏幕中央。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program centers a window
' on the screen
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim WIDTH As Integer = 250
    Dim HEIGHT As Integer = 150

    Public Sub New()

        Me.InitUI()

    End Sub

    Private Sub InitUI()

        Dim qdw As New QDesktopWidget

        Dim screenWidth As Integer = qdw.Width()
        Dim screenHeight As Integer = qdw.Height()

        Dim x As Integer = (screenWidth - WIDTH) / 2
        Dim y As Integer = (screenHeight - HEIGHT) / 2

        Me.SetWindowTitle("Center")
        Me.Resize(WIDTH, HEIGHT)
        Me.Move(x, y)
        Me.Show()

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

Qyoto 没有使窗口居中的单一方法。

Dim WIDTH As Integer = 250
Dim HEIGHT As Integer = 150

这两个常数定义了应用窗口的宽度和高度。

Dim qdw As New QDesktopWidget

QDesktopWidget类提供有关屏幕的信息。

Dim screenWidth As Integer = qdw.Width()
Dim screenHeight As Integer = qdw.Height()

在这里,我们确定屏幕的宽度和高度。

Dim x As Integer = (screenWidth - WIDTH) / 2
Dim y As Integer = (screenHeight - HEIGHT) / 2

在这里,我们计算居中窗口的 x,y 坐标。 为了使窗口在屏幕上居中,我们需要知道屏幕的大小和窗口的大小。

Me.Move(x, y)

我们将窗口移至计算出的 x,y 坐标。

退出按钮

在本节的最后一个示例中,我们将创建一个退出按钮。 当我们按下此按钮时,应用终止。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program creates a quit
' button. When we press the button,
' the application terminates. 
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Quit button")

        Me.InitUI()

        Me.Resize(250, 150)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim quit As New QPushButton("Quit", Me)

        Connect(quit, SIGNAL("clicked()"), qApp, SLOT("quit()"))
        quit.Move(30, 30)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们使用QPushButton。 这是一个非常常见的小部件。 它是矩形的,通常显示一个文本标签。

Me.InitUI()

我们将用户界面的创建委托给InitUI()方法。

Dim quit As New QPushButton("Quit", Me)

我们创建按钮小部件。 构造器的第一个参数是标签,按钮将显示该标签。 第二个参数是按钮的父窗口小部件。

Connect(quit, SIGNAL("clicked()"), qApp, SLOT("quit()"))

当我们点击按钮时,会发出clicked()信号。 Connect()方法将信号连接到对象的特定槽。 该方法的第一个参数是接收信号的对象。 在我们的例子中,它是应用对象。 第二个参数是方法,称为。 在我们的情况下,它是应用对象的quit()方法。 qApp是对应用对象的全局引用。

Quit button

图:退出按钮

本节介绍了使用 Visual Basic 语言的 Qyoto 库。

布局管理

原文: http://zetcode.com/gui/vbqyoto/layoutmanagement/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将介绍布局管理器。

在设计应用的 GUI 时,我们决定要使用哪些组件以及如何在应用中组织这些组件。 为了组织我们的组件,我们使用专门的不可见对象,称为布局管理器。 Qyoto 中有多个选项。 我们可以使用绝对定位,内置布局管理器或创建自定义布局管理器。 我们还可以使用 Qt Designer 直观地构建布局。

Qyoto 有一些重要的内置布局管理器。 QVBoxLayout类垂直排列小部件。 QHBoxLayout水平排列小部件。 QGridLayout类将小部件布置在网格中。 网格布局是最灵活的布局管理器。 盒子布局相互嵌套以创建复杂的布局。

绝对定位

在大多数情况下,程序员应使用布局管理器。 在某些情况下,我们可以使用绝对定位。 在绝对定位中,程序员以像素为单位指定每个小部件的位置和大小。 如果我们调整窗口大小,则小部件的大小和位置不会改变。 在各种平台上,应用看起来都不同,在 Linux 上看起来不错,在 Mac OS 上看起来不太正常。 在我们的应用中更改字体可能会破坏布局。 如果我们将您的应用翻译成另一种语言,则必须重做布局。 对于所有这些问题,仅在有理由时才使用绝对定位。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, we lay out widgets
' using absolute positioning
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QMainWindow

    Dim bardejov As QPixmap
    Dim rotunda As QPixmap 
    Dim mincol As QPixmap

    Public Sub New()

        Me.SetWindowTitle("Absolute")

        Me.InitUI()

        Me.Resize(300, 280)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        SetStyleSheet("QWidget { background-color: #414141 }")

        Try 
            bardejov = New QPixmap("bardejov.jpg")
            rotunda = New QPixmap("rotunda.jpg")
            mincol = New QPixmap("mincol.jpg")
        Catch e As Exception
            Console.WriteLine(e.Message)
            Environment.Exit(1)
        End Try

        Dim barLabel As New QLabel(Me)
        barLabel.SetPixmap(bardejov)
        barLabel.SetGeometry(20, 20, 120, 90)

        Dim rotLabel As New QLabel(Me)
        rotLabel.SetPixmap(rotunda)
        rotLabel.SetGeometry(40, 160, 120, 90)

        Dim minLabel As New QLabel(Me)
        minLabel.SetPixmap(mincol)
        minLabel.SetGeometry(170, 50, 120, 90)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在此示例中,我们使用绝对定位显示了三幅图像。

Dim barLabel As New QLabel(Me)
barLabel.SetPixmap(bardejov)

QLabel小部件用于保存图像。

barLabel.SetGeometry(20, 20, 120, 90)

我们使用SetGeometry()方法将标签放置在窗口上的x = 20y = 20处。 图片大小为120x90

调整窗口大小时,标签将保留其初始大小。

Absolute

图:绝对定位

按钮示例

在下面的示例中,我们将在窗口的右下角放置两个按钮。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, use box layouts
' to position two buttons in the
' bottom right corner of the window
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Buttons")

        Me.InitUI()

        Me.Resize(300, 150)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim vbox As New QVBoxLayout(Me)
        Dim hbox As New QHBoxLayout

        Dim ok As New QPushButton("OK", Me)
        Dim apply As New QPushButton("Apply", Me)

        hbox.AddWidget(ok, 1, Qt.AlignmentFlag.AlignRight)
        hbox.AddWidget(apply)

        vbox.AddStretch(1)
        vbox.AddLayout(hbox)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们使用嵌套框布局来获得我们想要的布局。

Dim vbox As New QVBoxLayout(Me)
Dim hbox As New QHBoxLayout

我们使用一个垂直框和一个水平框。

Dim ok As New QPushButton("OK", Me)
Dim apply As New QPushButton("Apply", Me)

这是两个将进入窗口右下角的按钮。

hbox.AddWidget(ok, 1, Qt.AlignmentFlag.AlignRight)

我们将确定按钮放入水平框中。 第二个参数是stretch因子。 它将扩大分配给“确定”按钮的区域。 它会占用所有可用空间。 在此区域内,按钮向右对齐。

vbox.AddStretch(1)

这条线创建了一个垂直扩展的白色空间,它将带有按钮的水平框推到底部。

vbox.AddLayout(hbox)

水平框嵌套在垂直框中。

Buttons example

图:按钮示例

Windows 示例

以下是嵌套框布局更复杂的示例。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, use box layouts
' to create a windows example
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Windows")

        Me.InitUI()

        Me.Resize(350, 300)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim vbox As New QVBoxLayout(Me)

        Dim vbox1 As New QVBoxLayout
        Dim hbox1 As New QHBoxLayout
        Dim hbox2 As New QHBoxLayout

        Dim windLabel As New QLabel("Windows", Me)
        Dim edit As New QTextEdit(Me)
        edit.SetEnabled(False)

        Dim activate As New QPushButton("Activate", Me)
        Dim close As New QPushButton("Close", Me)
        Dim help As New QPushButton("Help", Me)
        Dim ok As New QPushButton("OK", Me)

        vbox.AddWidget(windLabel)

        vbox1.AddWidget(activate)
        vbox1.AddWidget(close, 0, AlignmentFlag.AlignTop)
        hbox1.AddWidget(edit)
        hbox1.AddLayout(vbox1)

        vbox.AddLayout(hbox1)

        hbox2.AddWidget(help)
        hbox2.AddStretch(1)
        hbox2.AddWidget(ok)

        vbox.AddLayout(hbox2, 1)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在此布局中,我们使用两个垂直和水平框。

Dim vbox As New QVBoxLayout(Me)

这是示例的基本布局。

vbox.AddWidget(windLabel)

首先是标签小部件。 它只是转到垂直框的顶部。

vbox1.AddWidget(activate)
vbox1.AddWidget(close, 0, AlignmentFlag.AlignTop)
hbox1.AddWidget(edit)
hbox1.AddLayout(vbox1)

vbox.AddLayout(hbox1)

在窗口的中心部分,我们有一个文本编辑小部件和两个垂直排列的按钮。 这些按钮进入垂直框。 在此垂直框中,按钮与顶部对齐。 垂直框和文本编辑进入水平框。 该水平框转到标签窗口小部件正下方的基本垂直框。

hbox2.AddWidget(help)
hbox2.AddStretch(1)
hbox2.AddWidget(ok)

vbox.AddLayout(hbox2, 1)

帮助和确定按钮进入另一个水平框。 这两个按钮之间有一个扩大的空白区域。 同样,水平框转到基本垂直框。

Windows example

图:窗口示例

新文件夹示例

在最后一个示例中,我们使用QGridLayout管理器创建“新文件夹”布局示例。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, use the QGridLayout
' to create a New Folder example
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("New Folder")

        Me.InitUI()

        Me.Resize(350, 300)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim grid As New QGridLayout(Me)

        Dim nameLabel As New QLabel("Name", Me)
        Dim nameEdit As New QLineEdit(Me)
        Dim text As New QTextEdit(Me)
        Dim okButton As New QPushButton("OK", Me)
        Dim closeButton As New QPushButton("Close", Me)

        grid.AddWidget(nameLabel, 0, 0)
        grid.AddWidget(nameEdit, 0, 1, 1, 3)
        grid.AddWidget(text, 1, 0, 2, 4)
        grid.SetColumnStretch(1, 1)
        grid.AddWidget(okButton, 4, 2)
        grid.AddWidget(closeButton, 4, 3)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在我们的示例中,我们有一个标签,一行编辑,一个文本编辑和两个按钮。

Dim grid As New QGridLayout(Me)

我们创建QGridLayout管理器的实例。

grid.AddWidget(nameLabel, 0, 0)

我们将标签小部件放置在网格的第一个单元格中。 单元格从 0 开始计数。最后两个参数是行号和列号。

grid.AddWidget(nameEdit, 0, 1, 1, 3)

线编辑窗口小部件位于第一行第二列。 最后两个参数是行跨度和列跨度。 在水平方向上,小部件将跨越三列。

grid.SetColumnStretch(1, 1)

该方法的参数是列号和拉伸因子。 在这里,我们将拉伸因子 1 设置到第二列。 这意味着此列将占用所有剩余空间。 之所以这样设置,是因为我们希望按钮保持其初始大小。

New Folder example

图:新文件夹 example

在 Visual Basic Qyoto 教程的这一部分中,我们提到了小部件的布局管理。

Windows API 简介

原文: http://zetcode.com/gui/winapi/introduction/

这是 Windows API 教程。 本教程将教您使用 C 编程语言进行 Windows API 编程的基础知识和更高级的主题。 它不涵盖 MFC。 (Microsoft 基础类是一个广泛使用的 C++ 库,用于在 Windows 上开发 C++ 应用。)本教程已在 Windows 7 上创建并经过测试。示例使用 Pelles C 编译器构建。如果您打算阅读本教程,建议您下载并安装此编译器。 (这是一个免费软件。)如果要使用其他编译器,请确保它支持 C99 标准。

Windows API

Windows API 是用于创建 Windows 应用的应用编程接口。 为了创建 Windows 应用,我们必须下载 Windows SDK。 (以前称为 Platform SDK。)SDK(软件开发工具包)包含使用 Windows API 开发应用的头文件,库,示例,文档和工具。 Windows API 是为 C 和 C++ 编程语言创建的。 这是创建 Windows 应用的最直接方法。 (如果我们安装 Pelles C,则已经包含 Windows SDK。)

Windows API 可以分为几个区域:

  • 基础服务
  • 安全
  • 图形
  • 用户界面
  • 多媒体
  • Windows 外壳
  • 互联网

基本服务提供对 Windows 上基本资源的访问。 这些包括文件系统,设备,进程,线程,注册表或错误处理。安全区域提供功能,接口,对象和其他编程元素,用于认证,授权,加密和其他与安全相关的任务。图形子系统提供了将图形内容输出到监视器,打印机和其他输出设备的功能。用户界面提供创建窗口和控件的功能。多媒体组件提供了用于处理视频,声音和输入设备的工具。 Windows Shell 界面的功能允许应用访问操作系统外壳提供的功能。网络服务提供对 Windows OS 网络功能的访问。

Windows API 是 Windows 操作系统编程接口的抽象规范。 它由函数,联合,结构,数据类型,宏,常量和其他编程元素的声明组成。 Windows API 主要由 MSDN(Microsoft 开发者网络)描述,并且位于 Windows C 标头中。 Windows API 函数的正式实现位于动态库(DLL)中。 例如,Windows 系统目录中的kernel32.dlluser32.dllgdi32.dllshell32.dll。 Windows API 有第三方实现:最著名的是 Wine 项目和 ReactOS 项目。

Windows API 是一个动态实体。 随着 Windows OS 的每个新版本和新 Service Pack 的出现,功能数量不断增加。 服务器版本和操作系统的桌面版本之间也存在一些重要区别。 某些功能尚未正式记录。

Pelles C

Pelles C 是用于 C 编程语言的出色 C 编译器和集成开发环境(IDE)。 它同时支持 32 位 Windows(x86)和 64 位 Windows(x64)。 它实现了 C99 和 C11 标准。 Pelles C 具有集成的资源编辑器,位图,图标和光标编辑器以及十六进制转储编辑器。 它由瑞典开发商 Pelle Orinius 开发。 它带有 Windows SDK,因此我们可以立即开始创建 Windows 应用,而无需进行进一步的安装。

Pelles C 是免费软件。 我们可以从以下链接下载 Pelles C: Pelles C 下载

没有目标架构的错误

为了创建 Windows API 程序,我们必须启用 Microsoft 扩展。 默认情况下未启用它们。 因此,编译器将产生以下错误消息:fatal error #1014: #error: "No target architecture"。 要启用 Microsoft 扩展,我们转到项目选项,然后选择“编译器”选项卡。 在此选项卡中,我们选中“启用 Microsoft 扩展”框。

MSDN

MSDN(Microsoft 开发者网络)是 Windows 开发的中央门户。 它是与使用 Microsoft 工具开发 Windows 应用有关的大量材料。 (不包括 Qt4 或 Java Swing 之类的第三方软件。)它是 Windows API 的最完整参考。 以下两个链接是 Windows API 参考的良好入口点:桌面应用开发文档Windows API 列表

本章是 Windows API 的简介。

PyQt5 中的自定义小部件

原文: http://zetcode.com/gui/pyqt5/customwidgets/

PyQt5 具有丰富的小部件集。 但是,没有工具包可以向程序员提供在其应用中可能需要的所有小部件。 工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件或滑块。 如果需要更专业的小部件,我们必须自己创建它。

使用工具箱提供的绘图工具创建自定义窗口小部件。 有两种基本的可能性:程序员可以修改或增强现有的小部件,或者可以从头开始创建自定义小部件。

刻录小部件

这是一个小部件,我们可以在 Nero,K3B 或其他 CD/DVD 刻录软件中看到。

customwidget.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
ZetCode PyQt5 tutorial 

In this example, we create a custom widget.

Author: Jan Bodnar
Website: zetcode.com 
Last edited: August 2017
"""

from PyQt5.QtWidgets import (QWidget, QSlider, QApplication, 
    QHBoxLayout, QVBoxLayout)
from PyQt5.QtCore import QObject, Qt, pyqtSignal
from PyQt5.QtGui import QPainter, QFont, QColor, QPen
import sys

class Communicate(QObject):

    updateBW = pyqtSignal(int)

class BurningWidget(QWidget):

    def __init__(self):      
        super().__init__()

        self.initUI()

    def initUI(self):

        self.setMinimumSize(1, 30)
        self.value = 75
        self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]

    def setValue(self, value):

        self.value = value

    def paintEvent(self, e):

        qp = QPainter()
        qp.begin(self)
        self.drawWidget(qp)
        qp.end()

    def drawWidget(self, qp):

        MAX_CAPACITY = 700
        OVER_CAPACITY = 750

        font = QFont('Serif', 7, QFont.Light)
        qp.setFont(font)

        size = self.size()
        w = size.width()
        h = size.height()

        step = int(round(w / 10))

        till = int(((w / OVER_CAPACITY) * self.value))
        full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))

        if self.value >= MAX_CAPACITY:

            qp.setPen(QColor(255, 255, 255))
            qp.setBrush(QColor(255, 255, 184))
            qp.drawRect(0, 0, full, h)
            qp.setPen(QColor(255, 175, 175))
            qp.setBrush(QColor(255, 175, 175))
            qp.drawRect(full, 0, till-full, h)

        else:

            qp.setPen(QColor(255, 255, 255))
            qp.setBrush(QColor(255, 255, 184))
            qp.drawRect(0, 0, till, h)

        pen = QPen(QColor(20, 20, 20), 1, 
            Qt.SolidLine)

        qp.setPen(pen)
        qp.setBrush(Qt.NoBrush)
        qp.drawRect(0, 0, w-1, h-1)

        j = 0

        for i in range(step, 10*step, step):

            qp.drawLine(i, 0, i, 5)
            metrics = qp.fontMetrics()
            fw = metrics.width(str(self.num[j]))
            qp.drawText(i-fw/2, h/2, str(self.num[j]))
            j = j + 1

class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):      

        OVER_CAPACITY = 750

        sld = QSlider(Qt.Horizontal, self)
        sld.setFocusPolicy(Qt.NoFocus)
        sld.setRange(1, OVER_CAPACITY)
        sld.setValue(75)
        sld.setGeometry(30, 40, 150, 30)

        self.c = Communicate()        
        self.wid = BurningWidget()
        self.c.updateBW[int].connect(self.wid.setValue)

        sld.valueChanged[int].connect(self.changeValue)
        hbox = QHBoxLayout()
        hbox.addWidget(self.wid)
        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        self.setLayout(vbox)

        self.setGeometry(300, 300, 390, 210)
        self.setWindowTitle('Burning widget')
        self.show()

    def changeValue(self, value):

        self.c.updateBW.emit(value)        
        self.wid.repaint()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

在我们的示例中,我们有一个QSlider和一个自定义小部件。 滑块控制自定义窗口小部件。 此小部件以图形方式显示了介质的总容量和可供我们使用的可用空间。 我们的自定义窗口小部件的最小值是 1,最大值是OVER_CAPACITY。 如果达到值MAX_CAPACITY,我们将开始绘制红色。 这通常表示过度燃烧。

刻录小部件位于窗口的底部。 这可以通过使用一个QHBoxLayout和一个QVBoxLayout来实现。

class BurningWidget(QWidget):

    def __init__(self):      
        super().__init__()        

它基于QWidget小部件的刻录小部件。

self.setMinimumSize(1, 30)

我们更改小部件的最小大小(高度)。 默认值对我们来说有点小。

font = QFont('Serif', 7, QFont.Light)
qp.setFont(font)

我们使用的字体比默认字体小。 这更适合我们的需求。

size = self.size()
w = size.width()
h = size.height()

step = int(round(w / 10))

till = int(((w / OVER_CAPACITY) * self.value))
full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))

我们动态绘制小部件。 窗口越大,刻录的窗口小部件越大,反之亦然。 这就是为什么我们必须计算在其上绘制自定义窗口小部件的窗口小部件的大小的原因。 till参数确定要绘制的总大小。 该值来自滑块小部件。 它占整个面积的一部分。 full参数确定我们开始用红色绘制的点。

实际图纸包括三个步骤。 我们绘制黄色或红色和黄色矩形。 然后,我们绘制垂直线,将小部件分为几个部分。 最后,我们画出表示介质容量的数字。

metrics = qp.fontMetrics()
fw = metrics.width(str(self.num[j]))
qp.drawText(i-fw/2, h/2, str(self.num[j]))

我们使用字体指标来绘制文本。 我们必须知道文本的宽度,以便使其围绕垂直线居中。

def changeValue(self, value):

    self.c.updateBW.emit(value)        
    self.wid.repaint()

当我们移动滑块时,将调用changeValue()方法。 在方法内部,我们发送带有参数的自定义updateBW信号。 该参数是滑块的当前值。 该值随后用于计算刻录小部件的容量。 然后将自定义窗口小部件重新粉刷。

The burning widget

图:刻录小部件

在 PyQt5 教程的这一部分中,我们创建了一个自定义小部件。

{% raw %}

Qyoto 中的小部件

原文: http://zetcode.com/gui/vbqyoto/widgets/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将介绍 Qyoto 小部件。

小部件是 GUI 应用的基本构建块。 多年来,几个小部件已成为所有 OS 平台上所有工具包中的标准。 例如,按钮,复选框或滚动条。 Qyoto 有一组丰富的小部件,可以满足大多数编程需求。 可以将更多专门的窗口小部件创建为自定义窗口小部件。

QCheckBox

QCheckBox是具有两种状态的窗口小部件:开和关。 开状态通过复选标记显示。 它用来表示一些布尔属性。 QCheckBox小部件提供一个带有文本标签的复选框。

' ZetCode Mono Visual Basic Qt tutorial

' This program toggles the title of the
' window with the QCheckBox widget
'
' author jan bodnar
' last modified April 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("QCheckBox")

        Me.InitUI()

        Me.Resize(250, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim cb As New QCheckBox("Show title", Me)
        cb.Move(50, 50)
        cb.SetCheckState(True)
        Connect(cb, SIGNAL("clicked(bool)"), Me, SLOT("OnToggle(bool)"))

    End Sub

    <Q_SLOT()> _
    Private Sub OnToggle(ByVal state As Boolean)

        If state
             Me.SetWindowTitle("QCheckBox")
        Else
             Me.SetWindowTitle("")
        End If

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在我们的示例中,我们在窗口上放置了一个复选框。 复选框显示/隐藏窗口的标题。

Me.SetWindowTitle("QCheckBox")

在构建窗口期间,我们为窗口设置标题。

Dim cb As New QCheckBox("Show title", Me)

QCheckBox小部件已创建。 构造器的第一个参数是其文本标签。 第二个参数是父窗口小部件。

cb.SetCheckState(True)

标题在应用的开始处可见。 因此,也必须选中该复选框。 我们使用SetCheckState()方法来选中该复选框。

Connect(cb, SIGNAL("clicked(bool)"), Me, SLOT("OnToggle(bool)"))

当我们单击复选框时,将发出clicked(bool)信号。 发出信号时,我们触发OnToggle()方法。

<Q_SLOT()> _
Private Sub OnToggle(ByVal state As Boolean)
...
End Sub

方法定义之前带有Q_SLOT()属性。 此属性通知编译器有关自定义槽的信息。

If state
    Me.SetWindowTitle("QCheckBox")
Else
    Me.SetWindowTitle("")
End If

根据复选框的状态,我们显示或隐藏窗口的标题。

QCheckBox

图:QCheckBox

QLabel

QLabel小部件用于显示文本或图像。 没有用户交互。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program shows lyrics on the
' window
'
' author jan bodnar
' last modified April 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("You know I'm no Good")

        Me.InitUI()

        Me.Resize(250, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim text As String
        text = "Meet you downstairs in the bar and heard" + vbNewLine + _
"your rolled up sleeves and your skull t-shirt" + vbNewLine + _
"You say why did you do it with him today?" + vbNewLine + _
"and sniff me out like I was Tanqueray" + vbNewLine + _
"" + vbNewLine + _
"cause you're my fella, my guy" + vbNewLine + _
"hand me your stella and fly" + vbNewLine + _
"by the time I'm out the door" + vbNewLine + _
"you tear men down like Roger Moore" + vbNewLine + _
"" + vbNewLine + _
"I cheated myself" + vbNewLine + _
"like I knew I would" + vbNewLine + _
"I told ya, I was trouble" + vbNewLine + _
"you know that I'm no good" 

        Dim label As New QLabel(text, Me)
        label.Font = New QFont("Purisa", 9)

        Dim vbox As New QVBoxLayout()
        vbox.AddWidget(label)
        SetLayout(vbox)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们的示例在窗口中显示了歌曲的歌词。

Dim text As String
text = "Meet you downstairs in the bar and heard" + vbNewLine + _
"your rolled up sleeves and your skull t-shirt" + vbNewLine + _
...

我们定义了多行文字。 与 C# ,Python 或 Ruby 不同,没有简单的结构可以用 Visual Basic 语言创建多行文本。 若要在 Visual Basic 中创建多行文本,我们使用vbNewLine打印常量,+连接字符和_行终止字符。

Dim label As New QLabel(text, Me)
label.Font = New QFont("Purisa", 9)

我们创建标签小部件并更改其字体。

Dim vbox As New QVBoxLayout()
vbox.AddWidget(label)
SetLayout(vbox)

代替手动编码标签的位置和大小,我们将标签放入盒子布局中。

QLabel

图:QLabel

QLineEdit

QLineEdit是一个小部件,允许输入和编辑单行纯文本。 QLineEdit小部件具有撤消/重做,剪切/粘贴和拖放功能。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program demonstrates the 
' QLineEdit widget. Text entered in the QLineEdit
' widget is shown in a QLabel widget.
'
' author jan bodnar
' last modified April 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim label As QLabel

    Public Sub New()

        Me.InitUI()

        Me.SetWindowTitle("QLineEdit")
        Me.Resize(250, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        label = New QLabel(Me)

        Dim edit As New QLineEdit(Me)
        Connect(edit, SIGNAL("textChanged(QString)"), Me, _
            SLOT("OnChanged(QString)"))

        edit.Move(60, 100)
        label.Move(60, 40)

    End Sub

    <Q_SLOT()> _
    Private Sub OnChanged(ByVal text As String)

        label.SetText(text)
        label.AdjustSize()

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在我们的示例中,我们显示了两个小部件。 行编辑和标签小部件。 输入到行编辑中的文本显示在标签窗口小部件中。

Dim edit As New QLineEdit(Me)

QLineEdit小部件已创建。

Connect(edit, SIGNAL("textChanged(QString)"), Me, _
    SLOT("OnChanged(QString)"))

当我们在行编辑中键入或删除某些文本时,将触发OnChanged()方法。 该方法采用字符串参数。

<Q_SLOT()> _
Private Sub OnChanged(ByVal text As String)

    label.SetText(text)
    label.AdjustSize()

End Sub

OnChanged()方法中,我们将行编辑的内容设置为标签窗口小部件。 AdjustSize()方法确保所有文本都是可见的。

QLineEdit widget

图:QLineEdit小部件

ToggleButton

切换按钮是设置了可检查标志的按钮。 切换按钮是具有两种状态的按钮。 已按下但未按下。 通过单击可以在这两种状态之间切换。 在某些情况下此功能非常合适。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program uses toggle buttons to 
' change the background color of
' a widget
'
' author jan bodnar
' last modified April 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim square As QWidget
    Dim color As QColor

    Dim redb As QPushButton
    Dim greenb As QPushButton
    Dim blueb As QPushButton

    Public Sub New()

        Me.InitUI()

        Me.SetWindowTitle("Toggle buttons")
        Me.Resize(350, 240)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        color = New QColor()

        redb = New QPushButton("Red", Me)
        redb.Checkable = True
        greenb = New QPushButton("Green", Me)
        greenb.Checkable = True
        blueb = New QPushButton("Blue", Me)
        blueb.Checkable = True

        Connect(redb, SIGNAL("toggled(bool)"), Me, SLOT("OnToggled()"))
        Connect(greenb, SIGNAL("toggled(bool)"), Me, SLOT("OnToggled()"))
        Connect(blueb, SIGNAL("toggled(bool)"), Me, SLOT("OnToggled()"))

        square = New QWidget(Me)
        square.SetStyleSheet("QWidget { background-color: black }")

        redb.Move(30, 30)
        greenb.Move(30, 80)
        blueb.Move(30, 130)
        square.SetGeometry(150, 25, 150, 150)

    End Sub

    <Q_SLOT()> _
    Private Sub OnToggled()

        Dim red As Integer = color.Red()
        Dim green As Integer = color.Green()
        Dim blue As Integer = color.Blue()

        If redb.Checked 
            red = 255
        Else 
            red = 0
        End If

        If greenb.Checked
            green = 255
        Else 
            green = 0
        End If

        If blueb.Checked
            blue = 255
        Else 
            blue = 0
        End If

        color = New QColor(red, green, blue)

        Dim sheet As String = String.Format("QWidget {{ background-color: {0} }}", _
            color.Name())
        square.SetStyleSheet(sheet)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在代码示例中,我们使用三个切换按钮来更改矩形小部件的颜色。

Dim square As QWidget
Dim color As QColor

Dim redb As QPushButton
Dim greenb As QPushButton
Dim blueb As QPushButton

我们定义了五个对象。 正方形小部件是QWidget,它显示颜色。 color变量用于保存颜色值。 这三个按钮是切换按钮,用于混合颜色值。

redb = New QPushButton("Red", Me)
redb.Checkable = True

我们创建一个QPushButton小部件。 Checkable属性将按钮更改为切换按钮。

Connect(redb, SIGNAL("toggled(bool)"), Me, SLOT("OnToggled()"))
Connect(greenb, SIGNAL("toggled(bool)"), Me, SLOT("OnToggled()"))
Connect(blueb, SIGNAL("toggled(bool)"), Me, SLOT("OnToggled()"))

所有三个按钮都插入到一个方法调用中,即OnToggled()方法。

square = New QWidget(Me)
square.SetStyleSheet("QWidget { background-color: black }")

我们创建方形小部件。 一开始是黑色的。 在 Qyoto 中,我们使用样式表来自定义小部件的外观。

OnToggled()方法内部,我们确定颜色值并将正方形小部件更新为新颜色。

Dim red As Integer = color.Red()
Dim green As Integer = color.Green()
Dim blue As Integer = color.Blue()

在这里,我们确定方形小部件的当前颜色。

If redb.Checked 
    red = 255
Else 
    red = 0
End If

根据红色切换按钮的状态,更改颜色的红色部分。

color = New QColor(red, green, blue)

我们创建一个新的颜色值。

Dim sheet As String = String.Format("QWidget {{ background-color: {0} }}", _
    color.Name())

我们使用 Visual Basic 格式对象创建适当的样式表。

square.SetStyleSheet(sheet)

正方形的颜色已更新。

Toggle buttons

图:开关按钮

QComboBox

QComboBox是一个小部件,允许用户从选项列表中进行选择。 这是一个显示当前项目的选择小部件,可以弹出可选择项目的列表。 组合框可能是可编辑的。 它以占用最少屏幕空间的方式向用户显示选项列表。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, we use the QComboBox
' widget to select an option. 
' The selected option is shown in the
' QLabel widget
'
' author jan bodnar
' last modified April 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim label As QLabel

    Public Sub New()

        Me.SetWindowTitle("QComboBox")

        Me.InitUI()

        Me.Resize(250, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        label = New QLabel("Ubuntu", Me)

        Dim combo As New QComboBox(Me)
        combo.AddItem("Ubuntu")
        combo.AddItem("Mandriva")
        combo.AddItem("Fedora")
        combo.AddItem("Red Hat")
        combo.AddItem("Gentoo")

        combo.Move(50, 30)
        label.Move(50, 100)

        Connect(combo, SIGNAL("activated(QString)"), _
                 Me, SLOT("OnActivated(QString)"))

    End Sub

    <Q_SLOT()> _
    Private Sub OnActivated(ByVal text As String)

        label.SetText(text)
        label.AdjustSize()

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在我们的代码示例中,我们有两个小部件。 组合框和标签小部件。 从组合框中选择的选项显示在标签中。

label = New QLabel("Ubuntu", Me)

这是一个标签,它将显示组合框中当前选择的选项。

Dim combo As New QComboBox(Me)

我们创建QComboBox小部件的实例。

combo.AddItem("Ubuntu")
combo.AddItem("Mandriva")
combo.AddItem("Fedora")
combo.AddItem("Red Hat")
combo.AddItem("Gentoo")

组合框将填充值。

Connect(combo, SIGNAL("activated(QString)"), _
          Me, SLOT("OnActivated(QString)"))

当我们从组合框中选择一个选项时,将触发OnActivated()方法。

<Q_SLOT()> _
Private Sub OnActivated(ByVal text As String)

    label.SetText(text)
    label.AdjustSize()

End Sub

OnActivated()方法中,我们将标签小部件更新为从组合框中选择的当前字符串。

QComboBox widget

图:QComboBox小部件

在 Visual Basic Qyoto 教程的这一部分中,我们介绍了几个 Qyoto 小部件。

{% endraw %}

Qyoto 中的菜单和工具栏

原文: http://zetcode.com/gui/vbqyoto/menustoolbars/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将使用菜单和工具栏。

菜单栏是 GUI 应用中最可见的部分之一。 它是位于各个菜单中的一组命令。 在控制台应用中,您必须记住所有这些神秘命令,在这里,我们将大多数命令分组为逻辑部分。 有公认的标准可以进一步减少学习新应用的时间。 菜单将我们可以在应用中使用的命令分组。 使用工具栏可以快速访问最常用的命令。

简单菜单

第一个示例将显示一个简单的菜单。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program shows a simple
' menu. It has one action, which
' will terminate the program, when
' selected. 
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QMainWindow

    Public Sub New()

        Me.SetWindowTitle("Simple menu")

        Me.InitUI()

        Me.Resize(250, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim quit As New QAction("&Quit", Me)

        Dim file As QMenu = Me.MenuBar().AddMenu("&File")
        file.AddAction(quit)

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app as New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们有一个菜单栏,一个菜单和一个动作。 为了使用菜单,我们必须继承QMainWindow小部件。

Dim quit As New QAction("&Quit", Me)

此代码行创建一个QAction。 每个QMenu具有一个或多个动作对象。 注意 AND 字符(&)。 它为以下项目创建快捷方式: Alt + Q 。 它还强调了Q字符。 下拉菜单中的文件时,该快捷方式处于活动状态。

Dim file As QMenu = Me.MenuBar().AddMenu("&File")
file.AddAction(quit)

我们创建一个QMenu对象。 &字符创建快捷方式: Alt + F 。 连续的快捷键 Alt + FAlt + Q 退出了应用。

Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

当我们从菜单中选择此选项时,应用退出。

Simple menu

图:简单菜单

创建一个子菜单

子菜单是插入另一个菜单对象的菜单。 下一个示例对此进行了演示。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program creates 
' a submenu
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QMainWindow

    Public Sub New()

        Me.SetWindowTitle("Submenu")

        Me.InitUI()

        Me.Resize(280, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim quit As New QAction("&Quit", Me)

        Dim file As QMenu = MenuBar().AddMenu("&File")
        Dim impm As New QMenu("Import")

        Dim seeds As New QAction("Import news feed...", Me)
        Dim marks As New QAction("Import bookmarks...", Me)
        Dim mail As New QAction("Import mail...", Me)

        impm.AddAction(seeds)
        impm.AddAction(marks)
        impm.AddAction(mail)

        file.AddMenu(impm)
        file.AddAction(quit)

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在示例中,文件菜单的子菜单中有三个选项。

Dim file As QMenu = MenuBar().AddMenu("&File")
Dim impm As New QMenu("Import")

我们有两个QMenu对象。 文件菜单和导入菜单。

Dim seeds As New QAction("Import news feed...", Me)
Dim marks As New QAction("Import bookmarks...", Me)
Dim mail As New QAction("Import mail...", Me)

我们创建三个动作对象。

impm.AddAction(seeds)
impm.AddAction(marks)
impm.AddAction(mail)

我们将动作对象添加到导入菜单中。

file.AddMenu(impm)

最后,我们将导入菜单添加到文件菜单中。

Submenu

图:子菜单

图像,菜单,分隔符

在以下示例中,我们将进一步增强以前的应用。 我们将在菜单中添加图标,使用快捷方式和分隔符。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program shows image
' menu items, a shorcut and a separator
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QMainWindow

    Public Sub New()

        Me.SetWindowTitle("Image menu")

        Me.InitUI()

        Me.Resize(280, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim newpix As New QIcon("new.png")
        Dim openpix As New QIcon("open.png")
        Dim quitpix As New QIcon("quit.png")

        Dim newa As New QAction(newpix, "&New", Me)
        Dim open As New QAction(openpix, "&Open", Me)
        Dim quit As New QAction(quitpix, "&Quit", Me)

        quit.Shortcut = New QKeySequence("Ctrl+Q")    

        Dim file As QMenu = MenuBar().AddMenu("&File")
        file.AddAction(newa)
        file.AddAction(open)
        file.AddSeparator()
        file.AddAction(quit)

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在我们的示例中,我们有一个包含三个动作的菜单。 如果我们选择退出操作,则实际上只有退出操作才可以执行某些操作。 我们还创建了分隔符和 Ctrl + Q 快捷方式,它们将终止应用。

Dim newpix As New QIcon("new.png")
Dim openpix As New QIcon("open.png")
Dim quitpix As New QIcon("quit.png")

这些是我们将在应用中使用的 PNG 图像。

Dim newa As New QAction(newpix, "&New", Me)
Dim open As New QAction(openpix, "&Open", Me)
Dim quit As New QAction(quitpix, "&Quit", Me)

在这里,我们创建三个动作对象。 第一个参数是QIcon

quit.Shortcut = New QKeySequence("Ctrl+Q") 

这行创建一个快捷方式。 通过按下此快捷方式,我们将运行退出操作,这将终止应用。

file.AddSeparator()

我们创建一个分隔符。 分隔符是一条水平线,它使我们能够将菜单操作分组为一些逻辑部分。

Images, shortcut and a separator

图:图像 s, shortcut and a separator

工具栏

QToolBar类提供了一个可移动面板,其中包含一组控件,这些控件提供对应用操作的快速访问。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program creates a 
' toolbar
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QMainWindow

    Public Sub New()

        Me.SetWindowTitle("Toolbar")

        Me.InitUI()

        Me.Resize(280, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim newpi As New QIcon("new.png")
        Dim openpi As New QIcon("open.png")
        Dim quitpi As New QIcon("quit.png")

        Dim toolbar As QToolBar = AddToolBar("main toolbar")
        toolbar.AddAction(newpi, "New File")
        toolbar.AddAction(openpi, "Open File")
        toolbar.AddSeparator()
        Dim quit As QAction = toolbar.AddAction(quitpi, _
            "Quit Application")

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app as New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们创建一个带有三个动作对象和一个分隔符的工具栏。

Dim newpi As New QIcon("new.png")
Dim openpi As New QIcon("open.png")
Dim quitpi As New QIcon("quit.png")

工具栏动作对象将显示这些图标。

Dim toolbar As QToolBar = AddToolBar("main toolbar")

QMainWindow类的AddToolBar()方法为应用创建一个工具栏。 文本字符串为工具栏命名。 此名称用于引用此工具栏,因为一个应用中可以有多个工具栏。 如果右键单击窗口区域,我们将看到一个可检查的选项,该选项显示/隐藏工具栏。

toolbar.AddSeparator()

我们创建一个垂直分隔符。

Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

当我们单击退出操作对象时,应用终止。

Toolbar

图:工具栏

撤销重做

以下示例演示了如何停用工具栏上的工具栏按钮。 这是 GUI 编程中的常见做法。 例如,保存按钮。 如果我们将文档的所有更改都保存到磁盘上,则在大多数文本编辑器中,“保存”按钮将被停用。 这样,应用会向用户指示所有更改都已保存。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program disables/enables
' toolbuttons on a toolbar
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QMainWindow

    Dim clicks As Integer = 0
    Dim undoButton As QToolButton
    Dim redoButton As QToolButton

    Public Sub New()

        Me.SetWindowTitle("Undo redo")

        Me.InitUI()

        Me.Resize(280, 200)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim undoi As New QIcon("undo.png")
        Dim redoi As New QIcon("redo.png")
        Dim quitpi As New QIcon("quit.png")

        Dim toolbar As New QToolBar
        undoButton = New QToolButton
        redoButton = New QToolButton

        Dim undoAction As New QAction(undoi, "Undo", undoButton)
        Dim redoAction As New QAction(redoi, "Redo", redoButton)

        undoButton.SetDefaultAction(undoAction)
        redoButton.SetDefaultAction(redoAction)

        toolbar.AddSeparator()
        toolbar.AddWidget(undoButton)
        toolbar.AddWidget(redoButton)

        Dim quit As QAction = toolbar.AddAction(quitpi, "Quit Application")

        Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))

        Connect(undoButton, SIGNAL("triggered(QAction*)"), _
            Me, SLOT("Count(QAction*)"))
        Connect(redoButton, SIGNAL("triggered(QAction*)"), _
            Me, SLOT("Count(QAction*)"))

        AddToolBar(toolbar)

    End Sub

    <Q_SLOT()> _
    Private Sub Count(ByVal action As QAction)

        If "Undo".Equals(action.Text)
            clicks -= 1
        Else 
            clicks += 1
        End If

        If clicks <= 0 
            undoButton.SetDisabled(True)
            redoButton.SetDisabled(False)
        End If

        If clicks >= 5 
            undoButton.SetDisabled(False)
            redoButton.SetDisabled(True)
        End If

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在我们的示例中,我们有三个QAction对象和一个分隔符。 在撤消或重做按钮上单击几下后,它们将被停用。 外观上,按钮显示为灰色。

Dim clicks As Integer = 0

clicks变量确定哪个按钮被激活或停用。

Connect(undoButton, SIGNAL("triggered(QAction*)"), _
    Me, SLOT("Count(QAction*)"))
Connect(redoButton, SIGNAL("triggered(QAction*)"), _
    Me, SLOT("Count(QAction*)"))

单击工具栏按钮,将发射triggered()信号。 我们将此信号连接到Count()方法。 它接收触发它的QAction对象。

If "Undo".Equals(action.Text)
    clicks -= 1
Else 
    clicks += 1
End If

撤消工具栏按钮从clicks变量中减去 1。 重做添加 1。根据clicks变量的值,我们启用/禁用工具栏按钮。

If clicks <= 0 
    undoButton.SetDisabled(True)
    redoButton.SetDisabled(False)
End If

SetDisabled()方法激活或停用工具栏按钮。

Undo redo

图:撤销和重做

在 Visual Basic Qyoto 教程的这一部分中,我们提到了菜单和工具栏。

{% raw %}

Qyoto 对话框

原文: http://zetcode.com/gui/vbqyoto/dialogs/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将使用对话框。

对话框窗口或对话框是大多数现代 GUI 应用必不可少的部分。 对话被定义为两个或更多人之间的对话。 在计算机应用中,对话框是一个窗口,用于与应用“对话”。 对话框用于输入数据,修改数据,更改应用设置等。对话框是用户与计算机程序之间进行通信的重要手段。

MessageDialog

消息框是方便的对话框,可向应用的用户提供消息。 该消息由文本和图像数据组成。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program shows
' QMessageBox dialogs
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Message boxes")

        Me.InitUI()

        Me.Resize(220, 90)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim grid As New QGridLayout(Me)
        grid.Spacing = 2

        Dim errb As New QPushButton("Error", Me)
        Dim warnb As New QPushButton("Warning", Me)
        Dim questb As New QPushButton("Question", Me)
        Dim infob As New QPushButton("Information", Me)
        Dim aboutb As New QPushButton("About", Me)

        grid.AddWidget(errb, 0, 0)
        grid.AddWidget(warnb, 0, 1)
        grid.AddWidget(questb, 1, 0)
        grid.AddWidget(infob, 1, 1)
        grid.AddWidget(aboutb, 2, 0)

        Connect(errb, SIGNAL("clicked()"), Me, SLOT("OnClicked()"))
        Connect(warnb, SIGNAL("clicked()"), Me, SLOT("OnClicked()"))
        Connect(questb, SIGNAL("clicked()"), Me, SLOT("OnClicked()"))
        Connect(infob, SIGNAL("clicked()"), Me, SLOT("OnClicked()"))
        Connect(aboutb, SIGNAL("clicked()"), Me, SLOT("OnClicked()"))

    End Sub

    <Q_SLOT()> _
    Private Sub OnClicked()

        Dim button As QPushButton = Sender()

        If "Error".Equals(button.Text())
            QMessageBox.critical(Me, "Error", "Error loading file!")
        Else If "Warning".Equals(button.Text())
            QMessageBox.warning(Me, "Warning", "Operation not permitted!")
        Else If "Question".Equals(button.Text())
            QMessageBox.question(Me, "Question", "Are you sure to quit?")
        Else If "Information".Equals(button.Text())
            QMessageBox.information(Me, "Information", "Download completed.")
        Else If "About".Equals(button.Text())
            QMessageBox.about(Me, "About", "ZetCode Qyoto Visual Basic tutorial.")        
        End If

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们使用GridLayout管理器来设置五个按钮的网格。 每个按钮显示一个不同的消息框。

Dim button As QPushButton = Sender()

在这里,我们确定哪个按钮称为ShowDialog()方法。

If "Error".Equals(button.Text())
    QMessageBox.critical(Me, "Error", "Error loading file!")

如果按下错误按钮,则会显示错误对话框。 我们使用QMessageBox类的静态方法来显示消息框。

Information message dialog

Warning message dialog

Question message dialog

Error message dialog

About message dialog

QInputDialog

QInputDialog类提供了一个简单的便捷对话框,可从用户那里获取单个值。 输入值可以是字符串,数字或列表中的项目。 必须设置标签以告知用户他们应该输入什么。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program shows
' QInputDialog dialogs
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim edit As QLineEdit

    Public Sub New()

        Me.SetWindowTitle("QInputDialog")

        Me.InitUI()

        Me.Resize(300, 150)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        Dim show As New QPushButton("Dialog", Me)

        Connect(show, SIGNAL("clicked()"), Me, SLOT("ShowDialog()"))

        show.FocusPolicy = FocusPolicy.NoFocus
        show.Move(20, 20)

        edit = New QLineEdit(Me)
        edit.Move(130, 22)

    End Sub

    <Q_SLOT()> _
    Private Sub ShowDialog()

        Dim text As String = QInputDialog.GetText( _
                Me, "Input Dialog", "Enter your name")

        If text <> Nothing AndAlso text.Trim() <> String.Empty
            edit.SetText(text)
        End If

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在代码示例中,我们有一个按钮和一行编辑。 该按钮显示一个输入对话框。 我们得到一些文本,文本显示在行编辑小部件中。

Dim text As String = QInputDialog.GetText( _
        Me, "Input Dialog", "Enter your name")

GetText()静态方法创建输入对话框。 对话框中的文本存储在text变量中。

If text <> Nothing AndAlso text.Trim() <> String.Empty
    edit.SetText(text)
End If

在更新行编辑之前,请确保text变量不为null且不为空,并且不仅由空格组成。

Input dialog

图:输入对话框

QColorDialog

QColorDialog类提供用于指定颜色的对话框小部件。 颜色对话框的功能是允许用户选择颜色。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, we use the
' QColorDialog to change the color
' of a label text
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim label As QLabel

    Public Sub New()

        Me.SetWindowTitle("QColorDialog")

        Me.InitUI()

        Me.Resize(300, 150)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        label = New QLabel("ZetCode Qyoto Visual Basic tutorial", Me)

        Dim vbox As New QVBoxLayout(Me)
        label.Alignment = AlignmentFlag.AlignCenter
        vbox.AddWidget(label)

    End Sub

    Protected Overrides Sub MousePressEvent(ByVal e As QMouseEvent)

        Dim color As QColor = QColorDialog.GetColor()

        If Not color.IsValid() Then
            Return
        End If

        Dim style As String = String.Format("QWidget {{ color: {0} }}", _
            color.Name())
        label.SetStyleSheet(style)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们在窗口中心显示一些文本。 通过单击窗口区域,我们显示一个颜色对话框。 我们将文本前景色更改为从对话框中选择的颜色。

Protected Overrides Sub MousePressEvent(ByVal e As QMouseEvent)
    ...
End Sub

为了接收我们窗口的鼠标按下事件,我们必须重写MousePressEvent()方法。

Dim color As QColor = QColorDialog.GetColor()

正在创建QColorDialog。 所选颜色存储在color变量中。

If Not color.IsValid() Then
    Return
End If

当按下取消按钮时,我们什么也不做。

Dim style As String = String.Format("QWidget {{ color: {0} }}", _
    color.Name())
label.SetStyleSheet(style)

在这里,我们更新标签文本的前景色。

QColorDialog

图:QColorDialog

QFontDialog

QFontDialog类提供用于选择字体的对话框小部件。

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, we use the
' QFontDialog to change the font
' of a label text
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Dim label As QLabel

    Public Sub New()

        Me.SetWindowTitle("QFontDialog")

        Me.InitUI()

        Me.Resize(300, 150)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Private Sub InitUI()

        label = New QLabel("ZetCode Qyoto Visual Basic tutorial", Me)

        Dim vbox As New QVBoxLayout(Me)
        label.Alignment = AlignmentFlag.AlignCenter
        vbox.AddWidget(label)

    End Sub

    Protected Overrides Sub MousePressEvent(ByVal e As QMouseEvent)

        Dim ok As Boolean = True

        Dim font As QFont = QFontDialog.GetFont(ok)

        If Not ok Then
            Return
        End If

        label.Font = font

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

此示例与上一个示例相似。 这次,我们更改文本的字体。

Dim font As QFont = QFontDialog.GetFont(ok)

正在创建QFontDialog。 当我们按下对话框的 OK 按钮时,将设置boolean ok变量。

If Not ok Then
    Return
End If

如果没有按下“确定”按钮,我们什么也不做。

label.Font = font

font字段存储所选字体。 我们将标签的字体更新为新选择的字体。

QFontDialog

图:QFontDialog

在 Visual Basic Qyoto 教程的这一部分中,我们使用了对话框窗口。

{% endraw %}

Qyoto 中的绘图

原文: http://zetcode.com/gui/vbqyoto/painting/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将进行绘图。

我们什么时候需要油漆? 在某些情况下,当我们需要从头开始创建小部件时。 在这种情况下,我们需要绘图。 或者我们想创建图表,特殊装饰,效果或小部件增强。

当我们在 Qyoto 库中进行绘图时,QPainter类非常有用。 绘图事件通过PaintEvent()方法接收。 若要进行自定义绘图,我们必须重新实现此方法。

图案

在《京都议定书》中,我们可以使用各种图案来填充形状的内部。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program draws nine rectangles.
' The interiors are filled with
' different built-in patterns.
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Patterns")

        Me.Resize(350, 280)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)

        Dim painter As New QPainter(Me)
        Me.DrawPatterns(painter)

        painter.End()

    End Sub

    Private Sub DrawPatterns(ByRef painter As QPainter)

        painter.SetPen(PenStyle.NoPen)

        painter.SetBrush(Qt.BrushStyle.HorPattern)
        painter.DrawRect(10, 15, 90, 60)

        painter.SetBrush(Qt.BrushStyle.VerPattern)
        painter.DrawRect(130, 15, 90, 60)

        painter.SetBrush(Qt.BrushStyle.CrossPattern)
        painter.DrawRect(250, 15, 90, 60)

        painter.SetBrush(Qt.BrushStyle.Dense7Pattern)
        painter.DrawRect(10, 105, 90, 60)

        painter.SetBrush(Qt.BrushStyle.Dense6Pattern)
        painter.DrawRect(130, 105, 90, 60)

        painter.SetBrush(Qt.BrushStyle.Dense5Pattern)
        painter.DrawRect(250, 105, 90, 60)

        painter.SetBrush(Qt.BrushStyle.BDiagPattern)
        painter.DrawRect(10, 195, 90, 60)

        painter.SetBrush(Qt.BrushStyle.FDiagPattern)
        painter.DrawRect(130, 195, 90, 60)

        painter.SetBrush(Qt.BrushStyle.DiagCrossPattern)
        painter.DrawRect(250, 195, 90, 60)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在代码示例中,我们将绘制九个矩形,并用不同的画笔图案填充它们。

Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)

    Dim painter As New QPainter(Me)
    Me.DrawPatterns(painter)

    painter.End()

End Sub

当需要重绘窗口区域时,将调用PaintEvent()方法。 当我们调整窗口大小,最大化或最小化窗口时,就会发生这种情况。在此方法中,我们创建了QPainter对象。 该对象用于完成 Qyoto 中的所有绘图。 绘图本身被委托给DrawPatterns()方法。 End()方法释放绘图时使用的资源。

painter.SetPen(PenStyle.NoPen)

笔对象用于绘制形状的轮廓。 在我们的示例中,我们将不使用笔。

painter.SetBrush(Qt.BrushStyle.HorPattern)

我们将水平图案设置为画笔。 画笔用于绘制形状的内部。

painter.DrawRect(10, 15, 90, 60)

我们使用当前的笔和画笔绘制一个矩形。 该方法的前两个参数是 x,y 坐标。 最后两个参数是矩形的宽度和高度。

Patterns

图:图案

形状

Qyoto 绘图 API 可以绘制各种形状。 以下编程代码示例将显示其中的一些。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program draws basic shapes
' available in Qyoto.
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Shapes")

        Me.Resize(350, 280)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)

        Dim painter As New QPainter(Me)
        Me.DrawShapes(painter)

        painter.End()

    End Sub

    Private Sub DrawShapes(ByRef painter As QPainter)

        painter.SetRenderHint(QPainter.RenderHint.Antialiasing)
        painter.SetPen(New QPen(New QBrush(New QColor("Gray")), 1))
        painter.SetBrush(New QBrush(New QColor("Gray")))

        Dim path1 As New QPainterPath()

        path1.MoveTo(5, 5)
        path1.CubicTo(40, 5,  50, 50,  99, 99)
        path1.CubicTo(5, 99,  50, 50,  5, 5)
        painter.DrawPath(path1)

        painter.DrawPie(130, 20, 90, 60, 30*16, 120*16)
        painter.DrawChord(240, 30, 90, 60, 0, 16*180)
        painter.DrawRoundRect(20, 120, 80, 50)

        Dim polygon As New QPolygon(5)
        polygon.SetPoint(0, 130, 140)
        polygon.SetPoint(1, 180, 170)
        polygon.SetPoint(2, 180, 140)
        polygon.SetPoint(3, 220, 110)
        polygon.SetPoint(4, 140, 100)

        painter.DrawPolygon(polygon)
        painter.DrawRect(250, 110, 60, 60)

        Dim baseline As New QPointF(20, 250)
        Dim font As New QFont("Georgia", 55)
        Dim path2 As New QPainterPath()

        path2.AddText(baseline, font, "Q")
        painter.DrawPath(path2)

        painter.DrawEllipse(140, 200, 60, 60)
        painter.DrawEllipse(240, 200, 90, 60)

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在此代码示例中,我们在窗口上绘制了九种不同的形状。 复杂路径,饼图,和弦,圆角矩形,多边形,矩形,基于字符的形状,圆形和椭圆形。

painter.SetRenderHint(QPainter.RenderHint.Antialiasing)

我们在示例中使用抗锯齿。 抗锯齿形状看起来更好,但是绘制它们需要更多时间。

painter.SetPen(New QPen(New QBrush(New QColor("Gray")), 1))
painter.SetBrush(New QBrush(New QColor("Gray")))

我们使用深灰色的笔和画笔绘制形状。

Dim path1 As New QPainterPath()

path1.MoveTo(5, 5)
path1.CubicTo(40, 5,  50, 50,  99, 99)
path1.CubicTo(5, 99,  50, 50,  5, 5)
painter.DrawPath(path1)

使用QPainterPath对象创建第一个复杂形状。 QPainterPath类为绘图操作提供了一个容器。 画家路径是由许多图形构造块(例如矩形,椭圆形,直线和曲线)组成的对象。

painter.DrawPie(130, 20, 90, 60, 30*16, 120*16)
painter.DrawChord(240, 30, 90, 60, 0, 16*180)
painter.DrawRoundRect(20, 120, 80, 50)

这三行画出一个饼图,一个和弦和一个圆角矩形。

Dim polygon As New QPolygon(5)
polygon.SetPoint(0, 130, 140)
polygon.SetPoint(1, 180, 170)
polygon.SetPoint(2, 180, 140)
polygon.SetPoint(3, 220, 110)
polygon.SetPoint(4, 140, 100)

painter.DrawPolygon(polygon)

在这里,我们创建一个多边形。

Dim baseline As New QPointF(20, 250)
Dim font As New QFont("Georgia", 55)
Dim path2 As New QPainterPath()

path2.AddText(baseline, font, "Q")
painter.DrawPath(path2)

这些线创建基于字符的形状。

painter.DrawEllipse(140, 200, 60, 60)
painter.DrawEllipse(240, 200, 90, 60)

这两条线分别创建一个圆和一个椭圆。

Shapes

图:形状

透明矩形

透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。

在计算机图形学中,我们可以使用 alpha 合成来实现透明效果。 Alpha 合成是将图像与背景组合以创建部分透明外观的过程。 合成过程使用 Alpha 通道。 (wikipedia.org,answers.com)

' ZetCode Mono Visual Basic Qt tutorial
'
' This program draws ten
' rectangles with different
' levels of transparency
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Transparent rectangles")

        Me.Resize(590, 90)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)

        Dim painter As New QPainter(Me)
        Me.DrawRectangles(painter)

        painter.End()

    End Sub

    Private Sub DrawRectangles(ByRef painter As QPainter)

        painter.SetPen(PenStyle.NoPen)

        For i As Integer = 1 To 10
            painter.SetBrush(New QBrush(New QColor(0, 0, 255, i*25)))
            painter.DrawRect(50*i, 20, 40, 40)
        Next

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在示例中,我们将绘制十个具有不同透明度级别的矩形。

painter.SetPen(PenStyle.NoPen)

我们不用笔。

For i As Integer = 1 To 10
    painter.SetBrush(New QBrush(New QColor(0, 0, 255, i*25)))
    painter.DrawRect(50*i, 20, 40, 40)
Next

QColor对象的最后一个参数是 alpha 透明度值。

Transparent rectangles

图:透明矩形

甜甜圈形状

在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program draws a donut
' shape
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Donut")

        Me.Resize(350, 280)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)

        Dim painter As New QPainter(Me)
        Me.DrawDonut(painter)

        painter.End()

    End Sub

    Private Sub DrawDonut(ByRef painter As QPainter)

        Dim color As New QColor()
        color.SetNamedColor("#333333")

        Dim pen As New QPen(color)
        pen.setWidthF(0.5)
        painter.SetPen(pen)

        painter.SetRenderHint(QPainter.RenderHint.Antialiasing)

        Dim h As Integer = Me.Height()
        Dim w As Integer = Me.Width()

        painter.Translate(New QPoint(w/2, h/2))

        For rot As Integer = 1 To 360 Step 5
            painter.DrawEllipse(-125, -40, 250, 80)
            painter.Rotate(5)
        Next

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

在此示例中,我们创建一个甜甜圈。 形状类似于曲奇,因此得名“甜甜圈”。

Dim color As New QColor()
color.SetNamedColor("#333333")

我们可以使用十六进制表示法来创建颜色对象。

Dim h As Integer = Me.Height()
Dim w As Integer = Me.Width()

在这里,我们确定窗口的宽度和高度。

painter.Translate(New QPoint(w/2, h/2))

我们将坐标系移到窗口的中间。 这样,我们使绘图在数学上更容易。

For rot As Integer = 1 To 360 Step 5
    painter.DrawEllipse(-125, -40, 250, 80)
    painter.Rotate(5)
Next

我们绘制一个椭圆对象 72 次。 每次,我们将椭圆旋转 5 度。 这将创建我们的甜甜圈形状。

Donut

图:多纳圈

绘制文字

在最后一个示例中,我们将在窗口上绘制文本。

' ZetCode Mono Visual Basic Qt tutorial
'
' This program draws text
' on the window
'
' author jan bodnar
' last modified May 2009
' website www.zetcode.com

Imports Qyoto

Public Class VBQApp 
    Inherits QWidget

    Public Sub New()

        Me.SetWindowTitle("Unfaitful")

        Me.Resize(300, 280)
        Me.Move(300, 300)
        Me.Show()

    End Sub

    Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent)

        Dim painter As New QPainter(Me)
        Me.DrawLyrics(painter)

        painter.End()

    End Sub

    Private Sub DrawLyrics(ByRef painter As QPainter)

        painter.SetBrush(New QBrush(new QColor(25, 25, 25)))
        painter.SetFont(New QFont("Purisa", 10))

        painter.DrawText(New QPoint(20, 30), _
                "I don't wanna do this anymore")
        painter.DrawText(New QPoint(20, 60), _
                "I don't wanna be the reason why")
        painter.DrawText(New QPoint(20, 90), _
                "Everytime I walk out the door")
        painter.DrawText(New QPoint(20, 120), _
                "I see him die a little more inside")
        painter.DrawText(New QPoint(20, 150), _
                "I don't wanna hurt him anymore")
        painter.DrawText(New QPoint(20, 180), _
                "I don't wanna take away his life")
        painter.DrawText(New QPoint(20, 210), _
                "I don't wanna be...") 
        painter.DrawText(New QPoint(20, 240), _
                "A murderer")

    End Sub

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

我们在窗口上画一首歌歌词。

painter.SetFont(New QFont("Purisa", 10))

我们为文本设置了 Purisa 字体。

painter.DrawText(New QPoint(20, 30), _
        "I don't wanna do this anymore")

DrawText()方法用于绘制文本。

Drawing text

图:绘制文本

在 Visual Basic Qyoto 编程教程的这一部分中,我们做了一些绘图。

Qyoto 中的自定义小部件

原文: http://zetcode.com/gui/vbqyoto/customwidget/

在 Visual Basic Qyoto 编程教程的这一部分中,我们将创建一个自定义窗口小部件。

工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 程序员必须自己创建此类小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。

刻录小部件

在下一个示例中,我们将创建一个自定义刻录小部件。 可以在 Nero 或 K3B 之类的应用中看到此小部件。 该小部件将从头开始创建。

burning.vb

Imports Qyoto

NameSpace Burning

Public Class Burning 
    Inherits QWidget

    Const PANEL_HEIGHT As Integer = 30
    Const DISTANCE As Integer = 19
    Const LINE_WIDTH As Integer = 5
    Const DIVISIONS As Integer = 10

    Const FULL_CAPACITY As Double = 700.0
    Const MAX_CAPACITY As Double = 750.0

    Dim redColor As New QColor(255, 175, 175)
    Dim yellowColor As New QColor(255, 255, 184)

    Dim parent As QWidget 

    Dim num() As String = { _
        "75", "150", "225", "300", _
        "375", "450", "525", "600", _
        "675" _
    }

    Public Sub New(ByVal parent As QWidget) 
        Me.parent = parent
        MinimumHeight = PANEL_HEIGHT
    End Sub

    Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent) 

        Dim painter As New QPainter(Me)

        Me.DrawWidget(painter)
        painter.End()

    End Sub

    Private Sub DrawWidget(ByVal painter As QPainter) 

        Dim burn As CustomWidget.VBQApp = CType(parent, CustomWidget.VBQApp)

        Dim slid_width As Double = burn.GetCurrentWidth()
        Dim width As Double = Size.Width()
        Dim move As Double = width / DIVISIONS

        Dim till As Double = (width / MAX_CAPACITY) * slid_width
        Dim full As Double = (width / MAX_CAPACITY) * FULL_CAPACITY

        If slid_width > FULL_CAPACITY

            painter.SetPen(New QPen(New QBrush(yellowColor), 1))
            painter.SetBrush(New QBrush(yellowColor))
            painter.DrawRect(New QRectF(0, 0, full, PANEL_HEIGHT))
            painter.SetPen(New QPen(New QBrush(redColor), 1))
            painter.SetBrush(New QBrush(redColor))
            painter.DrawRect(New QRectF(full+1, 0, till-full, PANEL_HEIGHT))

        Else

            If (slid_width > 0) 
               painter.SetPen(New QPen(New QBrush(yellowColor), 1))
               painter.SetBrush(New QBrush(yellowColor))
               painter.DrawRect(New QRectF(0, 0, till, PANEL_HEIGHT))
            End If

        End If

        painter.SetPen(New QColor(90, 90, 90))
        painter.SetBrush(BrushStyle.NoBrush)
        painter.DrawRect(0, 0, Size.Width()-1, PANEL_HEIGHT-1)

        Dim newFont As QFont = painter.Font()
        newFont.SetPointSize(7)
        painter.SetFont(newFont)

        Dim metrics As New QFontMetrics(newFont)

        For i As Integer = 1 to num.Length
            painter.DrawLine(New QLineF(i*move, 1, i*move, LINE_WIDTH))

            Dim w As Integer = metrics.Width(num(i-1))

            painter.DrawText(New QPointF(i*move-w/2, DISTANCE), num(i-1))
        Next

    End Sub

End Class

End Namespace

在这个文件中,我们创建了刻录小部件。

Public Class Burning 
    Inherits QWidget

自定义窗口小部件基于QWidget小部件。

Const PANEL_HEIGHT As Integer = 30
Const DISTANCE As Integer = 19
Const LINE_WIDTH As Integer = 5
Const DIVISIONS As Integer = 10

Const FULL_CAPACITY As Double = 700.0
Const MAX_CAPACITY As Double = 750.0

这些是重要的常数。 PANEL_HEIGHT定义自定义窗口小部件的高度。 DISTANCE是比例尺上的数字与其父边框顶部之间的距离。 LINE_WIDTH是垂直线的宽度。 DIVISIONS是秤的数量。 FULL_CAPACITY是媒体的容量。 达到目标后,就会发生过度刻录。 用红色显示。 MAX_CAPACITY是介质的最大容量。

Dim num() As String = { _
    "75", "150", "225", "300", _
    "375", "450", "525", "600", _
    "675" _
}

我们使用这些数字来构建刻录小部件的比例。

Protected Overrides Sub PaintEvent(ByVal e As QPaintEvent) 

    Dim painter As New QPainter(Me)

    Me.DrawWidget(painter)
    painter.End()

End Sub

自定义窗口小部件的图形委托给DrawWidget()方法。

Dim burn As CustomWidget.VBQApp = CType(parent, CustomWidget.VBQApp)

我们检索对父窗口小部件的引用。

Dim slid_width As Double = burn.GetCurrentWidth()

我们使用它来获取当前选定的滑块值。

Dim width As Double = Size.Width()

我们得到小部件的宽度。 自定义窗口小部件的宽度是动态的。 用户可以调整大小。

Dim till As Double = (width / MAX_CAPACITY) * slid_width
Dim full As Double = (width / MAX_CAPACITY) * FULL_CAPACITY

我们使用width变量进行转换。 在比例尺值和自定义小部件的度量之间。 请注意,我们使用浮点值。 我们在绘图中获得了更高的精度。

painter.SetPen(New QPen(New QBrush(redColor), 1))
painter.SetBrush(New QBrush(redColor))
painter.DrawRect(New QRectF(full+1, 0, till-full, PANEL_HEIGHT))

这三行画出红色矩形,表示过度燃烧。

painter.DrawRect(0, 0, Size.Width()-1, PANEL_HEIGHT-1)

这是小部件的周长。 外部矩形。

painter.DrawLine(New QLineF(i*move, 1, i*move, LINE_WIDTH))

在这里,我们画出小的垂直线。

Dim w As Integer = metrics.Width(num(i-1))

painter.DrawText(New QPointF(i*move-w/2, DISTANCE), num(i-1))

在这里,我们绘制刻度的数字。 为了精确定位数字,我们必须获得字符串的宽度。

main.vb

Imports Qyoto

' ZetCode Mono Visual Basic Qt tutorial
'
' In this program, we create
' a custom widget
'
' @author jan bodnar
' website zetcode.com
' last modified May 2009

NameSpace CustomWidget

Public Class VBQApp 
    Inherits QWidget

    Const MAX_CAPACITY As Integer = 750

    Dim slider As QSlider
    Dim widget As QWidget
    Dim cur_width As Integer

    Public Sub New()
        Me.SetWindowTitle("The Burning Widget")

        Me.InitUI()

        Me.Resize(370, 200)
        Me.Move(300, 300)
        Me.Show()
    End Sub

    Private Sub InitUI() 

       slider = New QSlider(Qt.Orientation.Horizontal , Me)
       slider.Maximum = MAX_CAPACITY
       slider.SetGeometry(50, 50, 130, 30)

       Connect(slider, SIGNAL("valueChanged(int)"), Me, _
                SLOT("ValueChanged(int)"))

       Dim vbox As New QVBoxLayout(Me)
       Dim hbox As New QHBoxLayout

       vbox.AddStretch(1)

       widget = New Burning.Burning(Me)
       hbox.AddWidget(widget, 0)

       vbox.AddLayout(hbox)

       SetLayout(vbox)

    End Sub

    <Q_SLOT()> _
    Public Sub ValueChanged(ByVal val As Integer) 
        cur_width = val
        widget.Repaint()
    End Sub

    Public Function GetCurrentWidth() As Integer
      Return cur_width
    End Function

    Public Shared Sub Main(ByVal args() As String)
        Dim qapp As New QApplication(args)
        Dim app As New VBQApp
        QApplication.Exec()
    End Sub

End Class

NameSpace CustomWidget

这是主文件。 在这里,我们创建滑块小部件并使用我们的自定义小部件。

widget = New Burning.Burning(Me)
hbox.AddWidget(widget, 0)

我们创建了刻录小部件的实例,并将其添加到水平框中。

<Q_SLOT()> _
Public Sub ValueChanged(ByVal val As Integer) 
    cur_width = val
    widget.Repaint()
End Sub

当滑块的值更改时,我们将其存储在cur_width变量中,然后重新绘制自定义窗口小部件。

Public Function GetCurrentWidth() As Integer
  Return cur_width
End Function

定制小部件调用此方法以获取实际的滑块值。

The Burning widget

图:刻录小部件

在 Visual Basic Qyoto 教程的这一部分中,我们演示了如何创建自定义窗口小部件。

posted @   绝不原创的飞龙  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
点击右上角即可分享
微信分享提示