ZetCode-GUI-教程-五-
ZetCode GUI 教程(五)
原文:ZetCode
PyGTK 中的小部件 II
在 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
小部件
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()
在上面的示例中,我们有HScale
和Image
小部件。 通过拖动比例尺,我们可以在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
小部件
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
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
在 PyGTK 教程的这一章中,我们完成了有关 PyGTK 小部件的讨论。
PyGTK 中的高级小部件
在 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
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
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
在 PyGTK 编程教程的这一章中,我们讨论的是高级 PyGTK 小部件。
PyGTK 中的对话框
在 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()
方法。
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
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
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,我们将获得颜色并修改标签的颜色。
图:颜色 electionDialog
在 PyGTK 编程教程的这一部分中,我们使用了 PyGTK 内置对话框。
Pango
在 PyGTK 编程教程的这一部分中,我们将探索 Pango 库。
Pango 是一个免费的开源计算库,可高质量呈现国际化文本。 可以使用不同的字体后端,从而允许跨平台支持。 (维基百科)
Pango 提供了用于Gdk
和Gtk
的高级字体和文本处理。
简单的例子
在第一个示例中,我们展示了如何更改标签小部件的字体。
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
系统字体
下一个代码示例显示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
小部件的模型创建期间,我们从字体家族数组中获取所有字体名称,并将它们放入列表存储中。
图:系统字体
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
属性
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 属性
在 PyGTK 编程库的这一章中,我们使用了 pango 库。
Pango II
在 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 库有自己的单元。 它们与小部件用来绘制图形或文本的方式不同。 我们必须用这个常数乘数字。
图:动画文本
使用标记语言
我们可以使用内置的标记语言来更改文本的属性。
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)
我们创建标签小部件并为其设置标记文本。
图:使用标记
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)
布局正在窗口上绘制。
图:布局
在 PyGTK 编程库的这一章中,我们进一步使用了 pango 库。
PyGTK 中的 Cario 绘图
在 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()
这会用一些蓝色填充圆圈的内部。
图:简单 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 轴。
图:基本形状
色彩
颜色是代表红色,绿色和蓝色(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()
我们创建一个矩形形状,并用先前指定的颜色填充它。
图:颜色
透明矩形
透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。
在计算机图形学中,我们可以使用 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 透明度。
图:透明矩形
灵魂伴侣
在下一个示例中,我们在窗口上绘制一些文本。
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()
方法将文本绘制到窗口上。
图:灵魂伴侣
在 PyGTK 编程库的这一章中,我们使用 Cairo 图形库进行绘制。
Cario 绘图 II
在 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()
方法将每个旋转和缩放操作彼此隔离。
图:多纳圈
渐变
在计算机图形学中,渐变是从浅到深或从一种颜色到另一种颜色的阴影的平滑混合。 在 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,我们再次开始用黑色绘图,直到结束。
图:渐变
泡泡
在以下示例中,我们创建一个粉扑效果。 该示例将显示一个不断增长的居中文本,该文本将从某个点逐渐淡出。 这是一个非常常见的效果,您经常可以在 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 值。
图:粉扑
反射
在下一个示例中,我们显示反射图像。 这种美丽的效果使人产生幻觉,好像图像在水中被反射一样。
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()
在绘制图像表面的当前片段时会考虑透明度。
图:反射
等待
在此示例中,我们使用透明效果创建一个等待演示。 我们将绘制 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()
这些代码行将绘制八行中的每行。
图:等待
在 PyGTK 编程库的这一章中,我们使用 Cairo 库进行了一些更高级的绘制。
PyGTK 中的贪食蛇游戏
在 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()
首先,我们将定义一些在游戏中使用的全局变量。
WIDTH
和HEIGHT
常数确定电路板的大小。 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()
方法中使用此变量来更改蛇对象的坐标。 还要注意,当蛇向右行驶时,我们不能立即向左转。
图:贪食蛇
这是使用 PyGTK 编程库编程的贪食蛇电脑游戏。
PyGTK 中的自定义小部件
工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。
客户程序员必须创建更专业的小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能:程序员可以修改或增强现有的小部件,或者可以从头开始创建自定义小部件。
刻录小部件
这是我们从头开始创建的小部件的示例。 可以在各种媒体刻录应用(例如 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
变量中以备后用。 我们重新绘制刻录的小部件。
图:刻录小部件
在本章中,我们在 PyGTK 中创建了一个自定义小部件。
PHP GTK 教程
这是 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
在这里,我们将继续介绍 PyQt5 小部件。 我们将介绍QPixmap
,QLineEdit
,QSplitter
和QComboBox
。
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
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
小部件
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_())
该示例显示了QComboBox
和QLabel
。 组合框具有五个选项的列表。 这些是 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
在 PyQt5 教程的这一部分中,我们介绍了QPixmap
,QLineEdit
,QSplitter
和QComboBox
。
PHP GTK 简介
在 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();
我们设置了应用。 创建无限循环。 从这一点开始,应用就坐下来,等待用户或系统的外部事件。 循环一直运行到终止为止。
图:简单
创建工具提示
第二个示例将显示一个工具提示。 工具提示是一个小的矩形窗口,它提供有关对象的简短信息。 它通常是一个 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()
(显示容器及其所有子代)。
图:工具提示 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 = 50
,y = 50
的固定容器中。
本节介绍了使用 PHP 语言的 GTK 库。
PHP GTK 中的布局管理
在本章中,我们将展示如何在窗口或对话框中布置窗口小部件。
在设计应用的 GUI 时,我们决定要使用哪些小部件以及如何在应用中组织这些小部件。 为了组织窗口小部件,我们使用专门的不可见窗口小部件,称为布局容器。 在本章中,我们将提到GtkAlignment
,GtkFixed
,GtkVBox
和GtkTable
。
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 = 20
,y = 20
坐标处。
w.add(fixed);
最后,我们将GtkFixed
容器添加到窗口中。
图:固定
按钮
在此代码示例中,我们将使用垂直框,水平框和对齐小部件。 水平框将小部件排列为一行。 同样,垂直框将其小部件放在一列中。 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);
在这里,我们将框架小部件放入垂直框中。 该方法的第一个参数是小部件,它被放置在框中。 以下三个参数是expand
,fill
和padding
。 expand
参数设置为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
成员会将所有可用空间放在水平框的左侧。 这将向右推两个按钮。 我们将水平框添加到对齐容器中,然后将对齐容器包装到垂直框中。 我们必须记住,对齐容器仅包含一个子窗口小部件。 这就是为什么我们必须使用水平框。
图:按钮
计算器骨架
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);
我们将表格小部件打包到垂直框中。
图:计算机骨架
窗口
接下来,我们将创建一个更高级的示例。 我们显示一个窗口,可以在 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);
最后,单击确定按钮。 它位于第四列和第五行。
图:窗口
在 PHP GTK 教程的这一部分中,我们提到了小部件的布局管理。
PHP GTK 中的小部件
在 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
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
小部件
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
小部件
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
在 PHP GTK 教程的这一章中,我们展示了一些基本的小部件。
PHP GTK 中的菜单和工具栏
在 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);
与其他工具包不同,我们必须自己照顾菜单栏的布局管理。 我们将菜单栏放入垂直框中。
图:简单菜单
子菜单
我们的最后一个示例演示了如何创建子菜单。 子菜单是另一个菜单中的菜单。
<?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);
子菜单有其自己的菜单项。
图:子菜单
图像菜单
在下一个示例中,我们将进一步探索菜单。 我们将图像和加速器添加到我们的菜单项中。 加速器是用于激活菜单项的键盘快捷键。
<?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);
这些行创建一个分隔符。 它用于将菜单项放入逻辑组。
图:图像 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()
方法的第一个参数是工具按钮。 第二个是工具栏上的位置。
图:工具栏
在 PHP GTK 教程的这一章中,我们展示了如何使用菜单和工具栏。
对话框
在 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()
方法。
图:信息消息对话框
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
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
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 绘图
在 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();
我们用当前颜色填充矩形的内部。
图:颜色
基本形状
下一个示例将一些基本形状绘制到窗口上。
<?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 轴。
图:基本形状
透明矩形
透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。
在计算机图形学中,我们可以使用 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 透明度。
图:透明矩形
甜甜圈
在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。
<?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()
方法将文本绘制到窗口上。
图:灵魂伴侣
在 PHP GTK 教程的这一章中,我们使用 Cairo 库进行绘图。
自定义小部件
工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 如果需要更专业的小部件,我们必须自己创建它。
使用工具箱提供的绘图工具创建自定义窗口小部件。 有两种可能性。 程序员可以修改或增强现有的小部件。 或者,他可以从头开始创建自定义窗口小部件。
刻录小部件
这是我们从头开始创建的小部件的示例。 它基于最小的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
变量中以备后用。 我们重新绘制刻录的小部件。
图:刻录小部件
在本章中,我们使用 GTK 和 PHP 编程语言创建了一个自定义窗口小部件。
贪食蛇
在 PHP GTK 编程教程的这一部分中,我们将创建一个贪食蛇游戏克隆。
贪食蛇是较旧的经典视频游戏。 它最初是在 70 年代后期创建的。 后来它被带到 PC 上。 在这个游戏中,玩家控制蛇。 目的是尽可能多地吃苹果。 蛇每次吃一个苹果,它的身体就会长大。 蛇必须避开墙壁和自己的身体。
开发
蛇的每个关节的大小为 10px。 蛇由光标键控制。 最初,蛇具有三个关节。 游戏立即开始。 游戏结束后,我们在窗口中心显示"Game Over"
消息。
该代码分为两个文件。 board.php
和nibbles.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);
WIDTH
和HEIGHT
常数确定电路板的大小。 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()
方法。
图:贪食蛇
这是用 GTK 库和 PHP 编程语言编程的贪食蛇电脑游戏。
C# Qyoto 教程
这是 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 介绍
在 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
。 我们单击配置和生成按钮。 将目录更改为构建目录。 运行make
和sudo 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();
这三行设置了应用。
图:工具提示
使窗口居中
在第二个示例中,我们将窗口置于屏幕中央。
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);
我们将窗口移至计算出的cx
,cy
坐标。
退出按钮
在本节的最后一个示例中,我们将创建一个退出按钮。 当我们按下此按钮时,应用终止。
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 坐标。 最后两个参数是按钮的宽度和高度。
图:退出按钮
本节介绍了使用 C# 语言编写的 Qyoto 库。
PyQt5 拖放
在 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()
方法来激活它。
图:简单 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 教程的这一部分专门用于拖放操作。
布局管理
在 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 = 20
,y = 20
处。
调整窗口大小时,标签将保留其初始大小。
图:绝对定位
按钮示例
在下面的示例中,我们将在窗口的右下角放置两个按钮。
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);
水平框嵌套在垂直框中。
图:按钮示例
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;
基本的垂直框设置为窗口的主要布局。
图:窗口示例
新文件夹示例
在最后一个示例中,我们使用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 设置到第二列。 这意味着此列将占用所有剩余空间。 之所以这样设置,是因为我们希望按钮保持其初始大小。
图:新文件夹 example
在 Qyoto C# 教程的这一部分中,我们提到了小部件的布局管理。
{% raw %}
Qyoto 中的小部件
在 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
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
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
小部件
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;
正方形的颜色已更新。
图:开关按钮
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
小部件
在 Qyoto C# 教程的这一部分中,我们介绍了几个 Qyoto 小部件。
{% endraw %}
Qyoto 中的菜单和工具栏
在 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 + F
, Alt + Q
终止应用。
Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"));
当我们从菜单中选择此选项时,应用终止。
图:简单菜单
创建一个子菜单
子菜单是插入另一个菜单对象的菜单。 下一个示例对此进行了演示。
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);
最后,我们将导入菜单添加到文件菜单中。
图:子菜单
图像,菜单,分隔符
在以下示例中,我们将进一步增强以前的应用。 我们将在菜单中添加图标,使用快捷方式和分隔符。
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();
我们创建一个分隔符。 分隔符是一条水平线,它使我们能够将菜单操作分组为一些逻辑部分。
图:图像 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()"));
当我们单击退出操作对象时,应用终止。
图:工具栏
撤销重做
以下示例演示了如何停用工具栏上的工具栏按钮。 这是 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()
方法激活或停用工具栏按钮。
图:撤销和重做
在 Qyoto C# 教程的这一部分中,我们提到了菜单和工具栏。
{% raw %}
Qyoto 对话框
在 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
类的静态方法来显示消息框。
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
且不为空,并且不仅由空格组成。
图:输入对话框
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
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
在 Qyoto C# 教程的这一部分中,我们使用了对话框窗口。
{% endraw %}
Qyoto 中的绘图
在 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 坐标。 最后两个参数是矩形的宽度和高度。
图:图案
形状
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);
这两条线分别创建一个圆和一个椭圆。
图:形状
透明矩形
透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。
在计算机图形学中,我们可以使用 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 透明度值。
图:透明矩形
绘制文字
在最后一个示例中,我们将在窗口上绘制文本。
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 = 20
,y = 30
处绘制文本。
图:绘制文本
在 Qyoto C# 编程教程的这一部分中,我们做了一些绘图。
Qyoto 中的绘图 II
在 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 度。 这将创建我们的甜甜圈形状。
图:多纳圈
灰度图像
在下面的示例中,我们将创建一个灰度图像。
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()
方法修改像素。 我们将灰色值用于颜色的红色,绿色和蓝色部分。
图:灰度图像
反射
在下一个示例中,我们显示反射图像。 该效果使人产生幻觉,好像图像在水中被反射一样。
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()
方法将图像上下翻转。 请注意,平移是图像高度的两倍。 这是必要的,因为缩放操作不仅会翻转图像,还会使图像向上移动。 要了解这一点,只需拍摄一张照片,将其放在桌子上并翻转即可。
图:反射图像
等待效果
在此示例中,我们使用透明效果创建一个等待演示。 我们将绘制 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();
}
每次调用计时器事件时,我们都会增加计数值并重新绘制窗口区域。
图:等待 effect
在 Qyoto C# 编程教程的这一部分中,我们结束了有关在 Qyoto 中绘图的讨论。
Qyoto 中的自定义小部件
在 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;
}
定制小部件调用此方法以获取实际的滑块值。
图:刻录小部件
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 图像。
图:Led 小部件显示“关闭”状态
在 Qyoto C# 教程的这一部分中,我们演示了如何创建自定义窗口小部件。
贪食蛇
在 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;
}
}
}
首先,我们将定义一些在游戏中使用的全局变量。
WIDTH
和HEIGHT
常数确定电路板的大小。 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();
}
}
在这个类中,我们设置了贪食蛇游戏。
图:贪食蛇
这是用 Qyoto 库和 C# 编程语言编程的贪食蛇电脑游戏。
Ruby Qt 教程
这是 Ruby Qt 教程。 在本教程中,您将学习使用 Ruby 语言在 Qt 中进行 GUI 编程的基础。 本教程适合初学者和中级程序员。
目录
Qt
Qt 是一个跨平台的应用开发框架。 用 Qt 开发的一些知名应用是 KDE,Opera,Google Earth 和 Skype。 Qt 于 1995 年 5 月首次公开发布。它具有双重许可。 这意味着,它可以用于创建开源应用以及商业应用。 Qt 工具箱是一个非常强大的工具箱。 它在开源社区中已经建立。
相关教程
在 ZetCode 上有完整的 Ruby 教程。 Ruby GTK 教程是 Ruby 支持的另一个 GUI 库的教程。 Qt4 教程以 C++ 语言展示了 Qt 库。
Ruby Qt 简介
在 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::Widget
。 Widget
类是所有用户界面对象的基类。 小部件是用户界面的原子。 它从窗口系统接收鼠标,键盘和其他事件。
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
这三行设置了应用。
图:工具提示
使窗口居中
在第二个示例中,我们将窗口置于屏幕中央。
#!/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
在这里,我们计算居中窗口的x
和y
坐标。 为了使窗口在屏幕上居中,我们需要知道屏幕的大小和窗口的大小。
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
是指向应用实例的全局指针。
图:退出按钮
本节介绍了使用 Ruby 语言的 Qt 工具包。
PyQt5 中的绘图
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
,我们可以在两个维度上对齐文本。
图:绘制文本
绘制点
点是可以绘制的最简单的图形对象。 这是窗口上的一个小地方。
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()
方法画点。
图:点
颜色
颜色是代表红色,绿色和蓝色(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 值。 第三个和第四个参数是矩形的宽度和高度。 该方法使用当前的笔和画笔绘制矩形。
图:颜色
笔
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 间隔等。
图:笔的样式
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()
方法绘制矩形。
图:笔刷
贝塞尔曲线
贝塞尔曲线是一条三次曲线。 可以使用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()
方法绘制最终路径。
图:贝塞尔曲线
在 PyQt5 教程的这一部分中,我们做了一些基本的绘图。
Ruby Qt 中的布局管理
在 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 = 20
,y = 20
处。
调整窗口大小时,标签将保留其初始大小。
图:绝对定位
按钮示例
在下面的示例中,我们将在窗口的右下角放置两个按钮。
#!/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
水平框嵌套在垂直框中。
图:按钮示例
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
基本的垂直框设置为窗口的主要布局。
图:窗口示例
新文件夹示例
在最后一个示例中,我们使用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 设置到第二列。 这意味着此列将占用所有剩余空间。 之所以这样设置,是因为我们希望按钮保持其初始大小。
图:新文件夹 example
在 Ruby Qt 教程的这一部分中,我们提到了小部件的布局管理。
Ruby Qt 中的小部件
在 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::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::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
小部件
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)
正方形的颜色已更新。
图:开关按钮
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
小部件
在 Ruby Qt 教程的这一部分中,我们介绍了几个 Qt 小部件。
菜单和工具栏
在 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 + F
, Alt + Q
退出了应用。
connect(quit, SIGNAL("triggered()"),
Qt::Application.instance, SLOT("quit()"))
当我们从菜单中选择此选项时,应用退出。
图:简单菜单
子菜单
子菜单是插入另一个菜单对象的菜单。 下一个示例对此进行了演示。
#!/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
最后,我们将导入菜单添加到文件菜单中。
图:子菜单
图像,菜单,分隔符
在以下示例中,我们将进一步增强以前的应用。 我们将在菜单中添加图标,使用快捷方式和分隔符。 请注意,默认情况下,可能会将 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
我们创建一个分隔符。 分隔符是一条水平线,它使我们能够将菜单操作分组为一些逻辑部分。
图:图像 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"
MainWindow
的addToolBar
方法为应用创建一个工具栏。 文本字符串为工具栏命名。 此名称用于引用此工具栏,因为一个应用中可以有多个工具栏。 如果右键单击窗口区域,我们将看到一个可检查的选项,该选项显示或隐藏工具栏。
toolbar.addSeparator
我们创建一个垂直分隔符。
connect(quit, SIGNAL("triggered()"),
Qt::Application.instance, SLOT("quit()"))
当我们单击退出操作对象时,应用终止。
图:工具栏
撤销重做
以下示例演示了如何停用工具栏上的工具栏按钮。 这是 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
方法激活或停用工具栏按钮。
图:撤销和重做
在 Ruby Qt 教程的这一部分中,我们提到了菜单和工具栏。
Ruby Qt 中的对话框
在 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
类的静态方法来显示消息框。
图:信息对话框
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
且不为空,并且不仅由空格组成。
图:输入对话框
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
在这里,我们更新标签文本的前景色。
图: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
我们将标签更新为新选择的字体。
图:Qt::FontDialog
在 Ruby Qt 教程的这一部分中,我们使用了对话框窗口。
用 Ruby Qt 绘图
在 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
方法完成绘制。 释放绘图时使用的所有资源。
图:图案
形状
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
这两条线分别创建一个圆和一个椭圆。
图:形状
透明矩形
透明度是能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。
在计算机图形学中,我们可以使用 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 透明度值。
图:透明矩形
甜甜圈形状
在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。
#!/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 度。 这将创建我们的甜甜圈形状。
图:多纳圈
绘制文字
在最后一个示例中,我们将在窗口上绘制文本。
#!/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
方法用于绘制文本。
图:绘制文本
在 Ruby Qt 编程教程的这一部分中,我们做了一些绘图。
Ruby Qt 中的自定义小部件
在 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
定制小部件调用此方法以获取实际的滑块值。
图:刻录小部件
在 Ruby Qt 教程的这一部分中,我们已经演示了如何创建自定义窗口小部件。
Ruby Qt 中的贪食蛇
在 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
首先,我们将定义一些在游戏中使用的常量。
WIDTH
和HEIGHT
常数确定电路板的大小。 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
文件中,我们设置了贪食蛇游戏。
图:贪食蛇
这是使用 Qt 库和 Ruby 编程语言编程的贪食蛇电脑游戏。
Visual Basic Qyoto 教程
这是 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 介绍
在 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()
这三行设置了应用。
图:工具提示
使窗口居中
在第二个示例中,我们将窗口置于屏幕中央。
' 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
是对应用对象的全局引用。
图:退出按钮
本节介绍了使用 Visual Basic 语言的 Qyoto 库。
布局管理
在 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 = 20
,y = 20
处。 图片大小为120x90
。
调整窗口大小时,标签将保留其初始大小。
图:绝对定位
按钮示例
在下面的示例中,我们将在窗口的右下角放置两个按钮。
' 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)
水平框嵌套在垂直框中。
图:按钮示例
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)
帮助和确定按钮进入另一个水平框。 这两个按钮之间有一个扩大的空白区域。 同样,水平框转到基本垂直框。
图:窗口示例
新文件夹示例
在最后一个示例中,我们使用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 设置到第二列。 这意味着此列将占用所有剩余空间。 之所以这样设置,是因为我们希望按钮保持其初始大小。
图:新文件夹 example
在 Visual Basic Qyoto 教程的这一部分中,我们提到了小部件的布局管理。
Windows API 简介
这是 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.dll
,user32.dll
,gdi32.dll
或shell32.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 中的自定义小部件
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
信号。 该参数是滑块的当前值。 该值随后用于计算刻录小部件的容量。 然后将自定义窗口小部件重新粉刷。
图:刻录小部件
在 PyQt5 教程的这一部分中,我们创建了一个自定义小部件。
{% raw %}
Qyoto 中的小部件
在 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
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
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
小部件
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)
正方形的颜色已更新。
图:开关按钮
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
小部件
在 Visual Basic Qyoto 教程的这一部分中,我们介绍了几个 Qyoto 小部件。
{% endraw %}
Qyoto 中的菜单和工具栏
在 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 + F
, Alt + Q
退出了应用。
Connect(quit, SIGNAL("triggered()"), qApp, SLOT("quit()"))
当我们从菜单中选择此选项时,应用退出。
图:简单菜单
创建一个子菜单
子菜单是插入另一个菜单对象的菜单。 下一个示例对此进行了演示。
' 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)
最后,我们将导入菜单添加到文件菜单中。
图:子菜单
图像,菜单,分隔符
在以下示例中,我们将进一步增强以前的应用。 我们将在菜单中添加图标,使用快捷方式和分隔符。
' 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()
我们创建一个分隔符。 分隔符是一条水平线,它使我们能够将菜单操作分组为一些逻辑部分。
图:图像 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()"))
当我们单击退出操作对象时,应用终止。
图:工具栏
撤销重做
以下示例演示了如何停用工具栏上的工具栏按钮。 这是 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()
方法激活或停用工具栏按钮。
图:撤销和重做
在 Visual Basic Qyoto 教程的这一部分中,我们提到了菜单和工具栏。
{% raw %}
Qyoto 对话框
在 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
类的静态方法来显示消息框。
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
且不为空,并且不仅由空格组成。
图:输入对话框
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
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
在 Visual Basic Qyoto 教程的这一部分中,我们使用了对话框窗口。
{% endraw %}
Qyoto 中的绘图
在 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 坐标。 最后两个参数是矩形的宽度和高度。
图:图案
形状
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)
这两条线分别创建一个圆和一个椭圆。
图:形状
透明矩形
透明性是指能够透视材料的质量。 了解透明度的最简单方法是想象一块玻璃或水。 从技术上讲,光线可以穿过玻璃,这样我们就可以看到玻璃后面的物体。
在计算机图形学中,我们可以使用 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 透明度值。
图:透明矩形
甜甜圈形状
在下面的示例中,我们通过旋转一堆椭圆来创建复杂的形状。
' 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 度。 这将创建我们的甜甜圈形状。
图:多纳圈
绘制文字
在最后一个示例中,我们将在窗口上绘制文本。
' 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()
方法用于绘制文本。
图:绘制文本
在 Visual Basic Qyoto 编程教程的这一部分中,我们做了一些绘图。
Qyoto 中的自定义小部件
在 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
定制小部件调用此方法以获取实际的滑块值。
图:刻录小部件
在 Visual Basic Qyoto 教程的这一部分中,我们演示了如何创建自定义窗口小部件。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程