ZetCode GUI 教程(二十五)

原文:ZetCode 协议:CC BY-NC-SA 4.0 Ruby GTK 中的自定义小部件 原文: http:zetcodeguirubygtkcustomwi

原文:ZetCode

协议:CC BY-NC-SA 4.0

Ruby GTK 中的自定义小部件

原文: http://zetcode/gui/rubygtk/customwidget/

工具箱通常仅提供最常见的窗口小部件,例如按钮,文本窗口小部件,滑块等。没有工具箱可以提供所有可能的窗口小部件。 程序员必须自己创建此类小部件。 他们使用工具箱提供的绘图工具来完成此任务。 有两种可能:程序员可以修改或增强现有的小部件,或者可以从头开始创建自定义小部件。

刻录小部件

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

custom.rb

#!/usr/bin/ruby

'''
ZetCode Ruby GTK tutorial

This example creates a custom widget.

Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''

require 'gtk3'

class Burning < Gtk::DrawingArea

    def initialize parent
        @parent = parent

        super()

        @num = [ "75", "150", "225", "300", 
            "375", "450", "525", "600", "675" ]

        set_size_request 1, 30
        signal_connect "draw" do
            on_draw
        end
    end

    def on_draw

        cr = window.create_cairo_context
        draw_widget cr
    end

    def draw_widget cr

        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 = allocation.width

        @cur_width = @parent.get_cur_value

        step = (width / 10.0).round

        till = (width / 750.0) * @cur_width
        full = (width / 750.0) * 700

        if @cur_width >= 700

            cr.set_source_rgb 1.0, 1.0, 0.72
            cr.rectangle 0, 0, full, 30
            cr.clip
            cr.paint
            cr.reset_clip

            cr.set_source_rgb 1.0, 0.68, 0.68
            cr.rectangle full, 0, till-full, 30
            cr.clip
            cr.paint
            cr.reset_clip

        else
            cr.set_source_rgb 1.0, 1.0, 0.72
            cr.rectangle 0, 0, till, 30
            cr.clip
            cr.paint
            cr.reset_clip
        end

        cr.set_source_rgb(0.35, 0.31, 0.24)

        for i in 1..@num.length
            cr.move_to i*step, 0
            cr.line_to i*step, 5
            cr.stroke

            te = cr.text_extents @num[i-1]
            cr.move_to i*step-te.width/2, 15
            cr.text_path @num[i-1]
            cr.stroke
        end         
    end
end

class RubyApp < Gtk::Window

    def initialize
        super

        set_title "Burning"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end

        set_size_request 350, 200        
        set_window_position :center

        @cur_value = 0

        vbox = Gtk::Box.new :vertical, 2

        scale = Gtk::Scale.new :horizontal
        scale.set_range 0, 750
        scale.set_digits 0
        scale.set_size_request 160, 35
        scale.set_value @cur_value

        scale.signal_connect "value-changed" do |w|
            on_changed w
        end

        fix = Gtk::Fixed.new
        fix.put scale, 50, 50

        vbox.pack_start fix

        @burning = Burning.new self
        vbox.pack_start @burning, :expand => false, 
            :fill => false, :padding => 0

        add vbox
        show_all
    end    

    def on_changed widget

        @cur_value = widget.value
        @burning.queue_draw
    end

    def get_cur_value
        return @cur_value
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main

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

@num = [ "75", "150", "225", "300", 
    "375", "450", "525", "600", "675" ]

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

@cur_width = @parent.get_cur_value

从父小部件中,我们获得了比例小部件的当前值。

till = (width / 750.0) * @cur_width
full = (width / 750.0) * 700

我们使用width变量在小数位的值和自定义小部件的度量之间进行转换。 请注意,我们使用浮点值-在绘图中获得更高的精度。 till参数确定要绘制的总大小。 该值来自滑块小部件。 它占整个面积的一部分。 full参数确定我们开始绘制红色的点。

cr.set_source_rgb 1.0, 1.0, 0.72
cr.rectangle 0, 0, till, 30
cr.clip
cr.paint
cr.reset_clip

我们绘制一个黄色矩形,直到介质充满的地方。

te = cr.text_extents @num[i-1]
cr.move_to i*step-te.width/2, 15
cr.text_path @num[i-1]
cr.stroke

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

def on_changed widget

    @cur_value = widget.value
    @burning.queue_draw
end

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

图:刻录小部件

在本章中,我们使用 GTK 和 Ruby 编程语言创建了一个自定义小部件。

Ruby GTK 中的贪食蛇

原文: http://zetcode/gui/rubygtk/nibbles/

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

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

开发

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

board.rb

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

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

class Board < Gtk::DrawingArea

    def initialize
        super

        override_background_color :normal, Gdk::RGBA.new(0, 0, 0, 1)

        signal_connect "draw" do  
            on_draw
        end

        init_game
    end

    def on_timer

        if @inGame
            check_apple
            check_collision
            move
            queue_draw
            return true
        else
            return false
        end
    end

    def init_game

        @left = false
        @right = true
        @up = false
        @down = false
        @inGame = true
        @dots = 3

        for i in 0..@dots
            $x[i] = 50 - i * 10
            $y[i] = 50
        end

        begin
            @dot = Cairo::ImageSurface.from_png "dot.png"
            @head = Cairo::ImageSurface.from_png "head.png"
            @apple = Cairo::ImageSurface.from_png "apple.png"
        rescue Exception => e
            puts "cannot load images"
            exit
        end

        locate_apple
        GLib::Timeout.add(DELAY) { on_timer }
     end   

    def on_draw 

        cr = window.create_cairo_context

        if @inGame
            draw_objects cr
        else
            game_over cr
        end      
    end

    def draw_objects cr

        cr.set_source_rgb 0, 0, 0
        cr.paint

        cr.set_source @apple, @apple_x, @apple_y
        cr.paint

        for z in 0..@dots
            if z == 0 
                cr.set_source @head, $x[z], $y[z]
                cr.paint
            else
                cr.set_source @dot, $x[z], $y[z]
                cr.paint
            end    
        end
    end

    def game_over cr

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

        cr.set_font_size 15
        te = cr.text_extents "Game Over"

        cr.set_source_rgb 65535, 65535, 65535

        cr.move_to w - te.width/2, h
        cr.show_text "Game Over"
    end

    def check_apple

        if $x[0] == @apple_x and $y[0] == @apple_y 
            @dots = @dots + 1
            locate_apple
        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 check_collision

        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 - DOT_SIZE
            @inGame = false
        end

        if $y[0] < 0
            @inGame = false
        end

        if $x[0] > WIDTH - DOT_SIZE
            @inGame = false
        end

        if $x[0] < 0
            @inGame = false
        end    
    end

    def locate_apple

        r = rand RAND_POS
        @apple_x = r * DOT_SIZE
        r = rand RAND_POS
        @apple_y = r * DOT_SIZE
    end

    def on_key_down event

        key = event.keyval

        if key == Gdk::Keyval::GDK_KEY_Left and not @right
            @left = true
            @up = false
            @down = false
        end

        if key == Gdk::Keyval::GDK_KEY_Right and not @left
            @right = true
            @up = false
            @down = false
        end

        if key == Gdk::Keyval::GDK_KEY_Up and not @down
            @up = true
            @right = false
            @left = false
        end

        if key == Gdk::Keyval::GDK_KEY_Down and not @up
            @down = true
            @right = false
            @left = false
        end
    end   
end

首先,我们将定义一些在游戏中使用的全局变量。 WIDTHHEIGHT常数确定Board的大小。 DOT_SIZE是苹果的大小和蛇的点。 ALL_DOTS常数定义Board上可能的最大点数。 RAND_POS常数用于计算苹果的随机位置。 DELAY常数确定游戏的速度。

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

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

init_game方法初始化游戏。

@left = false
@right = true
@up = false
@down = false
@inGame = true
@dots = 3

我们初始化我们在游戏中使用的变量。

for i in 0..@dots
    $x[i] = 50 - i * 10
    $y[i] = 50
end

我们给蛇关节初始坐标。 它总是从同一位置开始。

begin
    @dot = Cairo::ImageSurface.from_png "dot.png"
    @head = Cairo::ImageSurface.from_png "head.png"
    @apple = Cairo::ImageSurface.from_png "apple.png"
rescue Exception => e
    puts "cannot load images"
    exit
end

加载了必要的图像。

locate_apple

苹果进入初始随机位置。

GLib::Timeout.add(DELAY) { on_timer }

GLib::Timeout.add方法将on_timer方法设置为每DELAY毫秒调用一次。

if @inGame
    draw_objects cr
else
    game_over cr
end      

on_draw方法内部,我们检查@inGame变量。 如果是真的,我们绘制对象:苹果和蛇关节。 否则,我们显示"Game Over"文本。

def draw_objects cr

    cr.set_source_rgb 0, 0, 0
    cr.paint

    cr.set_source @apple, @apple_x, @apple_y
    cr.paint

    for z in 0..@dots
        if z == 0 
            cr.set_source @head, $x[z], $y[z]
            cr.paint
        else
            cr.set_source @dot, $x[z], $y[z]
            cr.paint
        end    
    end
end

draw_objects方法绘制苹果和蛇的关节。 蛇的第一个关节是其头部,用红色圆圈表示。

def check_apple

    if $x[0] == @apple_x and $y[0] == @apple_y 
        @dots = @dots + 1
        locate_apple
    end
end

check_apple方法检查蛇是否击中了苹果对象。 如果是这样,我们添加另一个蛇形关节并调用locate_apple方法,该方法随机放置一个新的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

如果向左移动,则磁头向左移动。

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

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 - DOT_SIZE
    @inGame = false
end

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

locate_apple方法在板上随机放置一个苹果。

r = rand RAND_POS

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

@apple_x = r * DOT_SIZE
...
@apple_y = r * DOT_SIZE

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

if @inGame
    check_apple
    check_collision
    move
    queue_draw
    return true
else
    return false
end

DELAY ms 会调用一次on_timer方法。 如果我们参与了游戏,我们将调用三种构建游戏逻辑的方法。 否则,我们返回false,它将停止计时器事件。

Board类的on_key_down方法中,我们确定按下的键。

if key == Gdk::Keyval::GDK_KEY_Left and not @right
    @left = true
    @up = false
    @down = false
end

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

nibbles.rb

#!/usr/bin/ruby

'''
ZetCode Ruby GTK tutorial

This is a simple Nibbles game
clone.

Author: Jan Bodnar
Website: www.zetcode.com
Last modified: May 2014
'''

require 'gtk3'
require './board'

class RubyApp < Gtk::Window

    def initialize
        super

        set_title "Nibbles"
        signal_connect "destroy" do 
            Gtk.main_quit 
        end

        @board = Board.new
        signal_connect "key-press-event" do |w, e|
            on_key_down w, e
        end

        add @board

        set_default_size WIDTH, HEIGHT
        set_window_position :center
        show_all
    end

    def on_key_down widget, event 

        key = event.keyval
        @board.on_key_down event
    end
end

Gtk.init
    window = RubyApp.new
Gtk.main

在这个类中,我们设置了贪食蛇游戏。

def on_key_down widget, event 

    key = event.keyval
    @board.on_key_down event
end

我们捕获按键事件,并将处理委托给电路板类的on_key_down方法。

图:贪食蛇

这是使用 GTK 库和 Ruby 编程语言编程的贪食蛇电脑游戏。

GTK# 教程

原文: http://zetcode/gui/gtksharp/

这是针对 C# 编程语言的 GTK# 教程。 本教程适合初学者和更高级的程序员。

目录

  • 简介
  • 第一步
  • 布局管理
  • 菜单
  • 工具栏
  • 事件
  • 小部件
  • 小部件 II
  • 高级小部件
  • 对话框
  • Pango
  • 使用 Cario 绘图
  • 使用 cairo II 绘制
  • 自定义小部件

GTK#

GTK# 是针对 C# 编程语言的 GTK+ 的包装。 该库有助于使用 Mono 或任何其他兼容的 CLR 构建图形 GNOME 应用。 使用 Gtk# 构建的应用将在许多平台上运行,包括 Linux,Microsoft Windows 和 Mac OSX。GTK# 是 Mono 计划的一部分。

Tweet

相关教程

C# 教程深入介绍了 C# 语言。 Mono C# Winforms 教程和 C# Qyoto 教程提供了 C# 语言的替代 GUI 工具箱。

GTK# 简介

原文: http://zetcode/gui/gtksharp/introduction/

这是 GTK# 编程入门教程。 本教程针对 C# 编程语言。 它已在 Linux 上创建并经过测试。 GTK# 编程教程适合新手和中级程序员。 这是本教程中使用的图像。

GTK+

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

GTK+ 本身取决于以下库。

  • Glib
  • Pango
  • ATK
  • GDK
  • GdkPixbuf
  • Cario

Glib是通用工具库。 它提供各种数据类型,字符串工具,启用错误报告,消息日志记录,使用线程和其他有用的编程功能。 Pango是一个使国际化的库。 ATK是辅助功能工具包。 该工具包提供的工具可帮助残障人士使用计算机。 GDK是底层图形系统提供的低级绘图和窗口功能的包装。 在 Linux 上,GDK 位于 X Server 和 GTK+ 库之间。 最近,它的许多功能已委托给 Cario 库。 GdkPixbuf库是用于图像加载和像素缓冲区操作的工具包。 Cario 是用于创建 2D 矢量图形的库。 自 2.8 版起,它已包含在 GTK+ 中。

Gnome 和 XFce 桌面环境已使用 GTK+ 库创建。 SWT 和 wxWidgets 是使用 GTK+ 的众所周知的编程框架。 使用 GTK+ 的著名软件应用包括 Firefox 或 Inkscape。

GTK#

GTK# 是针对 C# 编程语言的 GTK+ 的包装。 该库有助于使用 Mono 或任何其他兼容的 CLR 构建图形 GNOME 应用。 Gtk# 是一个事件驱动的系统,就像任何其他现代的窗口库一样,其中应用中的每个小部件都具有处理器方法,这些处理器方法在发生特定事件时被调用。 使用 Gtk# 构建的应用将在许多平台上运行,包括 Linux,Microsoft,Windows 和 Mac OSX。GTK# 是 Mono 计划的一部分。 Mono 中基本上有两个窗口小部件工具箱:Winforms 和 GTK# 。 GTK# 被认为是 Linux/Unix 操作系统的本机。

编译 GTK# 应用

我们使用 gmcs 编译器来编译我们的 GTK# 应用。

$ gmcs -pkg:gtk-sharp-2.0 -r:/usr/lib/mono/2.0/Mono.Cairo.dll application.cs

上一行编译了一个也使用 Cario 库的 GTK# 应用。

数据来源

  • go-mono
  • wikipedia

在 GTK# 教程的这一部分中,我们介绍了 GTK# 库。

PyQt5 中的布局管理

原文: http://zetcode/gui/pyqt5/layout/

布局管理是我们将小部件放置在应用窗口中的方式。 我们可以使用绝对定位或布局类放置小部件。 使用布局管理器管理布局是组织窗口小部件的首选方式。

绝对定位

程序员以像素为单位指定每个小部件的位置和大小。 使用绝对定位时,我们必须了解以下限制:

  • 如果我们调整窗口大小,则小部件的大小和位置不会改变
  • 在各种平台上,应用看起来可能有所不同
  • 在我们的应用中更改字体可能会破坏布局
  • 如果我们决定更改布局,则必须完全重做布局,这既繁琐又耗时

以下示例将小部件放置在绝对坐标中。

absolute.py

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

"""
ZetCode PyQt5 tutorial 

This example shows three labels on a window
using absolute positioning. 

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

import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication

class Example(QWidget):

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

        self.initUI()

    def initUI(self):

        lbl1 = QLabel('Zetcode', self)
        lbl1.move(15, 10)

        lbl2 = QLabel('tutorials', self)
        lbl2.move(35, 40)

        lbl3 = QLabel('for programmers', self)
        lbl3.move(55, 70)        

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Absolute')    
        self.show()

if __name__ == '__main__':

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

我们使用move()方法定位小部件。 在我们的例子中,这些是标签。 我们通过提供 x 和 y 坐标来定位它们。 坐标系的起点在左上角。 x 值从左到右增长。 y 值从上到下增长。

lbl1 = QLabel('Zetcode', self)
lbl1.move(15, 10)

标签窗口小部件位于x=15y=10处。

图:绝对定位

盒子布局

QHBoxLayoutQVBoxLayout是在水平和垂直方向排列小部件的基本布局类。

想象一下,我们想在右下角放置两个按钮。 为了创建这样的布局,我们使用一个水平框和一个垂直框。 为了创建必要的空间,我们添加了拉伸因子。

buttons.py

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

"""
ZetCode PyQt5 tutorial 

In this example, we position two push
buttons in the bottom-right corner 
of the window. 

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

import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, 
    QHBoxLayout, QVBoxLayout, QApplication)

class Example(QWidget):

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

        self.initUI()

    def initUI(self):

        okButton = QPushButton("OK")
        cancelButton = QPushButton("Cancel")

        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(okButton)
        hbox.addWidget(cancelButton)

        vbox = QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)

        self.setLayout(vbox)    

        self.setGeometry(300, 300, 300, 150)
        self.setWindowTitle('Buttons')    
        self.show()

if __name__ == '__main__':

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

该示例在窗口的右下角放置了两个按钮。 当我们调整应用窗口的大小时,它们会停留在该位置。 我们同时使用HBoxLayoutQVBoxLayout

okButton = QPushButton("OK")
cancelButton = QPushButton("Cancel")

在这里,我们创建两个按钮。

hbox = QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)

我们创建一个水平框布局,并添加一个拉伸因子和两个按钮。 拉伸在两个按钮之前增加了可拉伸的空间。 这会将它们推到窗口的右侧。

vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)

将水平布局放置在垂直布局中。 垂直框中的拉伸因子会将带有按钮的水平框推到窗口底部。

self.setLayout(vbox)

最后,我们设置窗口的主要布局。

图:按钮

QGridLayout

QGridLayout是最通用的布局类。 它将空间分为行和列。

calculator.py

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

"""
ZetCode PyQt5 tutorial 

In this example, we create a skeleton
of a calculator using QGridLayout.

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

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout, 
    QPushButton, QApplication)

class Example(QWidget):

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

        self.initUI()

    def initUI(self):

        grid = QGridLayout()
        self.setLayout(grid)

        names = ['Cls', 'Bck', '', 'Close',
                 '7', '8', '9', '/',
                '4', '5', '6', '*',
                 '1', '2', '3', '-',
                '0', '.', '=', '+']

        positions = [(i,j) for i in range(5) for j in range(4)]

        for position, name in zip(positions, names):

            if name == '':
                continue
            button = QPushButton(name)
            grid.addWidget(button, *position)

        self.move(300, 150)
        self.setWindowTitle('Calculator')
        self.show()

if __name__ == '__main__':

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

在我们的示例中,我们创建了一个按钮网格。

grid = QGridLayout()
self.setLayout(grid)

创建QGridLayout的实例,并将其设置为应用窗口的布局。

names = ['Cls', 'Bck', '', 'Close',
            '7', '8', '9', '/',
        '4', '5', '6', '*',
            '1', '2', '3', '-',
        '0', '.', '=', '+']

这些是稍后用于按钮的标签。

positions = [(i,j) for i in range(5) for j in range(4)]

我们在网格中创建位置列表。

for position, name in zip(positions, names):

    if name == '':
        continue
    button = QPushButton(name)
    grid.addWidget(button, *position)

使用addWidget()方法创建按钮并将其添加到布局。

图:计算机骨架

回顾示例

小部件可以跨越网格中的多个列或行。 在下一个示例中,我们将对此进行说明。

review.py

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

"""
ZetCode PyQt5 tutorial 

In this example, we create a bit
more complicated window layout using
the QGridLayout manager. 

author: Jan Bodnar
website: zetcode 
last edited: January 2015
"""

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

class Example(QWidget):

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

        self.initUI()

    def initUI(self):

        title = QLabel('Title')
        author = QLabel('Author')
        review = QLabel('Review')

        titleEdit = QLineEdit()
        authorEdit = QLineEdit()
        reviewEdit = QTextEdit()

        grid = QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(title, 1, 0)
        grid.addWidget(titleEdit, 1, 1)

        grid.addWidget(author, 2, 0)
        grid.addWidget(authorEdit, 2, 1)

        grid.addWidget(review, 3, 0)
        grid.addWidget(reviewEdit, 3, 1, 5, 1)

        self.setLayout(grid) 

        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Review')    
        self.show()

if __name__ == '__main__':

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

我们创建一个窗口,其中有三个标签,两个行编辑和一个文本编辑小部件。 使用QGridLayout完成布局。

grid = QGridLayout()
grid.setSpacing(10)

我们创建网格布局并设置小部件之间的间距。

grid.addWidget(reviewEdit, 3, 1, 5, 1)

如果我们将小部件添加到网格,则可以提供小部件的行跨度和列跨度。 在我们的例子中,我们使reviewEdit小部件跨越 5 行。

图:回顾 example

PyQt5 教程的这一部分专门用于布局管理。

GTK 的第一步

原文: http://zetcode/gui/gtksharp/firststeps/

在 GTK# 编程教程的这一部分中,我们将进行编程的第一步。 我们将创建简单的程序。

简单的例子

第一个代码示例是一个简单的示例,它显示了居中的窗口。

center.cs

using Gtk;

class SharpApp : Window {

    public SharpApp() : base("Center")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);

        DeleteEvent += delegate { Application.Quit(); };

        Show();    
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();        
        Application.Run();
    }
}

该代码示例在屏幕中央显示一个小窗口。

$ gmcs -pkg:gtk-sharp-2.0 center.cs

这是我们编译代码示例的方式。

using Gtk;

现在,我们可以直接使用Gtk名称空间中的对象。 我们可以写Window而不是Gtk.Window

class SharpApp : Window {

我们的应用基于SharpApp类。 该类继承自Window类。

public SharpApp() : base("Center")
{
    ...   
}

这是构造器。 它构建了我们的应用。 它还通过base()关键字调用其父构造器。

SetDefaultSize(250, 200);

这行为我们的窗口设置默认大小。

SetPosition(WindowPosition.Center);

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

DeleteEvent += delegate { Application.Quit(); };

我们将一个代理插入DeleteEvent。 当我们单击标题栏中的关闭按钮时,将触发此事件。 或按 Alt + F4 。 我们的代表永久退出了申请。

Show();

现在我们显示窗口。 在调用Show()方法之前,该窗口不可见。

public static void Main()
{
    Application.Init();
    new SharpApp();        
    Application.Run();
}

Main()方法是应用的入口点。 它启动并运行程序。

图标

在下一个示例中,我们显示应用图标。 大多数窗口管理器在标题栏的左上角以及任务栏上都显示图标。

icon.cs


using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Icon")
    {
        SetDefaultSize(250, 160);
        SetPosition(WindowPosition.Center);
        SetIconFromFile("web.png");

        DeleteEvent += new DeleteEventHandler(OnDelete);

        Show();      
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }

    void OnDelete(object obj, DeleteEventArgs args)
    {
        Application.Quit();
    }
}

该代码示例显示了应用图标。

SetIconFromFile("web.png");

SetIconFromFile()方法为窗口设置图标。 从当前工作目录中的磁盘加载映像。

DeleteEvent += new DeleteEventHandler(OnDelete);

这是另一种方式,我们如何将事件处理器插入事件。 只是有点冗长。

void OnDelete(object obj, DeleteEventArgs args)
{
    Application.Quit();
}

这是删除事件的事件处理器。

图:图标

按钮

在下一个示例中,我们将使用 GTK# 库进一步增强我们的编程技能。

buttons.cs

using Gtk;

class SharpApp : Window
{

    public SharpApp() : base("Buttons")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);

        DeleteEvent += delegate { Application.Quit(); };

        Fixed fix = new Fixed();

        Button btn1 = new Button("Button");
        btn1.Sensitive = false;
        Button btn2 = new Button("Button");
        Button btn3 = new Button(Stock.Close);
        Button btn4 = new Button("Button");
        btn4.SetSizeRequest(80, 40);

        fix.Put(btn1, 20, 30);
        fix.Put(btn2, 100, 30);
        fix.Put(btn3, 20, 80);
        fix.Put(btn4, 100, 80);

        Add(fix);
        ShowAll();
    }

    public static void Main() 
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

我们在窗口上显示四个不同的按钮。 我们将看到容器窗口小部件和子窗口小部件之间的区别,并将更改子窗口小部件的某些属性。

Fixed fix = new Fixed();

Fixed小部件是不可见的容器小部件。 其目的是包含其他子窗口小部件。

Button btn1 = new Button("Button");

Button是子窗口小部件。 子窗口小部件放置在容器内。

btn1.Sensitive = false;

我们使此按钮不敏感。 这意味着我们无法单击它。 图形化的小部件为灰色。

Button btn3 = new Button(Stock.Close);

第三个按钮在其区域内显示图像。 GTK# 库具有我们可以使用的内置图像库。

btn4.SetSizeRequest(80, 40);

在这里,我们更改按钮的大小。

fix.Put(btn1, 20, 30);
fix.Put(btn2, 100, 30);
...

在这里,我们将按钮小部件放置在固定容器小部件内。

Add(fix);

我们将Fixed容器设置为Window小部件的主要容器。

ShowAll();

我们可以调用ShowAll()方法,也可以在每个小部件上调用Show()方法。 包括容器。

图:按钮

在本章中,我们在 GTK# 编程库中创建了第一个程序。

GTK# 中的布局管理

原文: http://zetcode/gui/gtksharp/layout/

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

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

Fixed

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

fixed.cs

using Gtk;
using System;

class SharpApp : Window {

    private Gdk.Pixbuf rotunda;
    private Gdk.Pixbuf bardejov;
    private Gdk.Pixbuf mincol;

    public SharpApp() : base("Fixed")
    {
        SetDefaultSize(300, 280);
        SetPosition(WindowPosition.Center);
        ModifyBg(StateType.Normal, new Gdk.Color(40, 40, 40));
        DeleteEvent += delegate { Application.Quit(); };

        try {
            bardejov = new Gdk.Pixbuf("bardejov.jpg");
            rotunda = new Gdk.Pixbuf("rotunda.jpg");
            mincol = new Gdk.Pixbuf("mincol.jpg");
        } catch {
            Console.WriteLine("Images not found");
            Environment.Exit(1);
        }

        Image image1 = new Image(bardejov);
        Image image2 = new Image(rotunda);
        Image image3 = new Image(mincol);

        Fixed fix = new Fixed();

        fix.Put(image1, 20, 20);
        fix.Put(image2, 40, 160);
        fix.Put(image3, 170, 50);

        Add(fix);
        ShowAll();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

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

ModifyBg(StateType.Normal, new Gdk.Color(40, 40, 40));

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

bardejov = new Gdk.Pixbuf("bardejov.jpg");

我们将图像从磁盘加载到Gdk.Pixbuf对象。

Image image1 = new Image(bardejov);
Image image2 = new Image(rotunda);
Image image3 = new Image(mincol);

Image是用于显示图像的小部件。 它在构造器中使用Gdk.Pixbuf对象。

Fixed fix = new Fixed();

我们创建Fixed容器。

fix.Put(image1, 20, 20);

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

Add(fix);

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

图:固定

Alignment

Alignment容器控制其子窗口小部件的对齐方式和大小。

alignment.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Alignment")
    {
        SetDefaultSize(260, 150);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        VBox vbox = new VBox(false, 5);
        HBox hbox = new HBox(true, 3);

        Alignment valign = new Alignment(0, 1, 0, 0);
        vbox.PackStart(valign);

        Button ok = new Button("OK");
        ok.SetSizeRequest(70, 30);
        Button close = new Button("Close");

        hbox.Add(ok);
        hbox.Add(close);

        Alignment halign = new Alignment(1, 0, 0, 0);
        halign.Add(hbox);

        vbox.PackStart(halign, false, false, 3);

        Add(vbox);

        ShowAll();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

在代码示例中,我们在窗口的右下角放置了两个按钮。 为此,我们使用一个水平框和一个垂直框以及两个对齐容器。

Alignment valign = new Alignment(0, 1, 0, 0);

这会将子窗口小部件置于底部。

vbox.PackStart(valign);

在这里,我们将Alignment小部件放置到垂直框中。

HBox hbox = new HBox(true, 3);
...
Button ok = new Button("OK");
ok.SetSizeRequest(70, 30);
Button close = new Button("Close");

hbox.Add(ok);
hbox.Add(close);

我们创建一个水平框,并在其中放置两个按钮。

Alignment halign = new Alignment(1, 0, 0, 0);
halign.Add(hbox);

vbox.PackStart(halign, false, false, 3);

这将创建一个对齐容器,它将其子窗口小部件放在右侧。 我们将水平框添加到对齐容器中,然后将对齐容器包装到垂直框中。 我们必须记住,对齐容器仅包含一个子窗口小部件。 这就是为什么我们必须使用盒子。

图:对齐

Table

Table小部件按行和列排列小部件。

calculator.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Calculator")
    {
        SetDefaultSize(250, 230);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        VBox vbox = new VBox(false, 2);

        MenuBar mb = new MenuBar();
        Menu filemenu = new Menu();
        MenuItem file = new MenuItem("File");
        file.Submenu = filemenu;
        mb.Append(file);

        vbox.PackStart(mb, false, false, 0);

        Table table = new Table(5, 4, true);

        table.Attach(new Button("Cls"), 0, 1, 0, 1);
        table.Attach(new Button("Bck"), 1, 2, 0, 1);
        table.Attach(new Label(), 2, 3, 0, 1);
        table.Attach(new Button("Close"), 3, 4, 0, 1);

        table.Attach(new Button("7"), 0, 1, 1, 2);
        table.Attach(new Button("8"), 1, 2, 1, 2);
        table.Attach(new Button("9"), 2, 3, 1, 2);
        table.Attach(new Button("/"), 3, 4, 1, 2);

        table.Attach(new Button("4"), 0, 1, 2, 3);
        table.Attach(new Button("5"), 1, 2, 2, 3);
        table.Attach(new Button("6"), 2, 3, 2, 3);
        table.Attach(new Button("*"), 3, 4, 2, 3);

        table.Attach(new Button("1"), 0, 1, 3, 4);
        table.Attach(new Button("2"), 1, 2, 3, 4);
        table.Attach(new Button("3"), 2, 3, 3, 4);
        table.Attach(new Button("-"), 3, 4, 3, 4);

        table.Attach(new Button("0"), 0, 1, 4, 5);
        table.Attach(new Button("."), 1, 2, 4, 5);
        table.Attach(new Button("="), 2, 3, 4, 5);
        table.Attach(new Button("+"), 3, 4, 4, 5);

        vbox.PackStart(new Entry(), false, false, 0);
        vbox.PackEnd(table, true, true, 0);

        Add(vbox);
        ShowAll();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

我们使用Table小部件创建一个计算器框架。

Table table = new Table(5, 4, true);

我们创建一个具有 5 行 4 列的表小部件。 第三个参数是齐次参数。 如果设置为true,则表中的所有小部件都具有相同的大小。 所有窗口小部件的大小等于表容器中最大的窗口小部件。

table.Attach(new Button("Cls"), 0, 1, 0, 1);

我们在表格容器上附加一个按钮。 到表格的左上方单元格。 前两个参数是单元格的左侧和右侧,后两个参数是单元格的顶部和左侧。

vbox.PackEnd(table, true, true, 0);

我们将表格小部件打包到垂直框中。

图:计算机骨架

窗口

接下来,我们将创建一个更高级的示例。 我们显示一个窗口,可以在 JDeveloper IDE 中找到它。

windows.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Windows")
    {
        SetDefaultSize(300, 250);
        SetPosition(WindowPosition.Center);
        BorderWidth = 15;
        DeleteEvent += delegate { Application.Quit(); };

        Table table = new Table(8, 4, false);
        table.ColumnSpacing = 3;

        Label title = new Label("Windows");

        Alignment halign = new Alignment(0, 0, 0, 0);
        halign.Add(title);

        table.Attach(halign, 0, 1, 0, 1, AttachOptions.Fill, 
            AttachOptions.Fill, 0, 0);

        TextView wins = new TextView();
        wins.ModifyFg(StateType.Normal, new Gdk.Color(20, 20, 20));
        wins.CursorVisible = false;
        table.Attach(wins, 0, 2, 1, 3, AttachOptions.Fill | AttachOptions.Expand,
            AttachOptions.Fill | AttachOptions.Expand, 1, 1);

        Button activate = new Button("Activate");
        activate.SetSizeRequest(50, 30);
        table.Attach(activate, 3, 4, 1, 2, AttachOptions.Fill, 
            AttachOptions.Shrink, 1, 1);

        Alignment valign = new Alignment(0, 0, 0, 0);
        Button close = new Button("Close");
        close.SetSizeRequest(70, 30);
        valign.Add(close);
        table.SetRowSpacing(1, 3);
        table.Attach(valign, 3, 4, 2, 3, AttachOptions.Fill,
            AttachOptions.Fill | AttachOptions.Expand, 1, 1);

        Alignment halign2 = new Alignment(0, 1, 0, 0);
        Button help = new Button("Help");
        help.SetSizeRequest(70, 30);
        halign2.Add(help);
        table.SetRowSpacing(3, 6);
        table.Attach(halign2, 0, 1, 4, 5, AttachOptions.Fill, 
            AttachOptions.Fill, 0, 0);

        Button ok = new Button("OK");
        ok.SetSizeRequest(70, 30);
        table.Attach(ok, 3, 4, 4, 5, AttachOptions.Fill, 
            AttachOptions.Fill, 0, 0);

        Add(table);
        ShowAll();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

该代码示例显示了如何在 GTK# 中创建类似的窗口。

Table table = new Table(8, 4, false);
table.ColumnSpacing = 3;

该示例基于Table容器。 列之间将有 3px 的间距。

Label title = new Label("Windows");

Alignment halign = new Alignment(0, 0, 0, 0);
halign.Add(title);

table.Attach(halign, 0, 1, 0, 1, AttachOptions.Fill, 
    AttachOptions.Fill, 0, 0);

这段代码创建了一个向左对齐的标签。 标签放置在Table容器的第一行中。

TextView wins = new TextView();
wins.ModifyFg(StateType.Normal, new Gdk.Color(20, 20, 20));
wins.CursorVisible = false;
table.Attach(wins, 0, 2, 1, 3, AttachOptions.Fill | AttachOptions.Expand,
    AttachOptions.Fill | AttachOptions.Expand, 1, 1);

文本视图小部件跨越两行两列。 我们使小部件不可编辑并隐藏光标。

Alignment valign = new Alignment(0, 0, 0, 0);
Button close = new Button("Close");
close.SetSizeRequest(70, 30);
valign.Add(close);
table.SetRowSpacing(1, 3);
table.Attach(valign, 3, 4, 2, 3, AttachOptions.Fill,
    AttachOptions.Fill | AttachOptions.Expand, 1, 1);

我们将关闭按钮放在文本视图小部件旁边的第四列中。 (我们从零开始计数)将按钮添加到对齐小部件中,以便可以将其对齐到顶部。

图:窗口

在本章中,我们介绍了 GTK# 小部件的布局管理。

GTK 中的菜单

原文: http://zetcode/gui/gtksharp/menus/

在 GTK# 编程教程的这一部分中,我们将使用菜单。

菜单栏是 GUI 应用中最常见的部分之一。 它是位于各个菜单中的一组命令。 在控制台应用中,我们必须记住各种奥术命令,而在这里,我们将大多数命令分组为逻辑部分。 这些公认的标准可进一步减少学习新应用的时间。

简单菜单

在第一个示例中,我们将创建一个带有一个文件菜单的菜单栏。 该菜单将只有一个菜单项。 通过选择项目,应用退出。

simplemenu.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Simple menu")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        MenuBar mb = new MenuBar();

        Menu filemenu = new Menu();
        MenuItem file = new MenuItem("File");
        file.Submenu = filemenu;

        MenuItem exit = new MenuItem("Exit");
        exit.Activated += OnActivated;
        filemenu.Append(exit);

        mb.Append(file);

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(mb, false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnActivated(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

这是一个最小的菜单栏功能示例。

MenuBar mb = new MenuBar();

MenuBar小部件已创建。

Menu filemenu = new Menu();
MenuItem file = new MenuItem("File");
file.Submenu = filemenu;

创建顶层MenuItem

MenuItem exit = new MenuItem("Exit");
exit.Activated += OnActivated;
filemenu.Append(exit);

将创建出口MenuItem,并将其附加到文件MenuItem中。

mb.Append(file);

顶级MenuItem被附加到MenuBar小部件。

VBox vbox = new VBox(false, 2);
vbox.PackStart(mb, false, false, 0);

与其他工具包不同,我们必须自己照顾布局管理。 我们将菜单栏放入垂直框中。

图:简单菜单

图像菜单

在下一个示例中,我们将进一步探索菜单。 我们将图像和加速器添加到我们的菜单项中。 加速器是用于激活菜单项的键盘快捷键。

imagemenu.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Image menu")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        MenuBar mb = new MenuBar();

        Menu filemenu = new Menu();
        MenuItem file = new MenuItem("File");
        file.Submenu = filemenu;

        AccelGroup agr = new AccelGroup();
        AddAccelGroup(agr);

        ImageMenuItem newi = new ImageMenuItem(Stock.New, agr);
        newi.AddAccelerator("activate", agr, new AccelKey(
            Gdk.Key.n, Gdk.ModifierType.ControlMask, AccelFlags.Visible));
        filemenu.Append(newi);

        ImageMenuItem open = new ImageMenuItem(Stock.Open, agr);
        open.AddAccelerator("activate", agr, new AccelKey(
            Gdk.Key.n, Gdk.ModifierType.ControlMask, AccelFlags.Visible));
        filemenu.Append(open);

        SeparatorMenuItem sep = new SeparatorMenuItem();
        filemenu.Append(sep);

        ImageMenuItem exit = new ImageMenuItem(Stock.Quit, agr);
        exit.AddAccelerator("activate", agr, new AccelKey(
            Gdk.Key.q, Gdk.ModifierType.ControlMask, AccelFlags.Visible));

        exit.Activated += OnActivated;
        filemenu.Append(exit);

        mb.Append(file);

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(mb, false, false, 0);
        vbox.PackStart(new Label(), false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnActivated(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

我们的示例显示了具有三个子菜单项的顶级菜单项。 每个菜单项都有一个图像和一个加速器。 退出菜单项的加速器处于活动状态。

AccelGroup agr = new AccelGroup();
AddAccelGroup(agr);

要使用加速器,我们创建一个全局AccelGroup对象。 稍后将使用。

ImageMenuItem newi = new ImageMenuItem(Stock.New, agr);

ImageMenuItem已创建。 图片来自图片库。

exit.AddAccelerator("activate", agr, new AccelKey(
    Gdk.Key.q, Gdk.ModifierType.ControlMask, AccelFlags.Visible));

这将为退出菜单项创建 Ctrl + Q 加速器。

SeparatorMenuItem sep = new SeparatorMenuItem();
filemenu.Append(sep);

这些行创建一个分隔符。 它用于将菜单项分组为逻辑组。

图:图像 menu

CheckMenuItem

CheckMenuItem是带有复选框的菜单项。 它可以用于布尔属性。

checkmenuitem.cs

using Gtk;
using System;

class SharpApp : Window {

    private Statusbar statusbar;

    public SharpApp() : base("Check menu item")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        MenuBar mb = new MenuBar();

        Menu filemenu = new Menu();
        MenuItem file = new MenuItem("File");
        file.Submenu = filemenu;

        Menu viewmenu = new Menu();
        MenuItem view = new MenuItem("View");
        view.Submenu = viewmenu;

        CheckMenuItem stat = new CheckMenuItem("View Statusbar");
        stat.Toggle();
        stat.Toggled += OnStatusView;
        viewmenu.Append(stat);

        MenuItem exit = new MenuItem("Exit");
        exit.Activated += OnActivated;
        filemenu.Append(exit);

        mb.Append(file);
        mb.Append(view);

        statusbar = new Statusbar();
        statusbar.Push(1, "Ready");

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(mb, false, false, 0);
        vbox.PackStart(new Label(), true, false, 0);
        vbox.PackStart(statusbar, false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnStatusView(object sender, EventArgs args)
    {
        CheckMenuItem item = (CheckMenuItem) sender;

        if (item.Active) {
            statusbar.Show();
        } else {
            statusbar.Hide();
        }
    }

    void OnActivated(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

在我们的代码示例中,我们显示一个检查菜单项。 如果该复选框已激活,则显示状态栏小部件。 如果不是,状态栏将被隐藏。

CheckMenuItem stat = new CheckMenuItem("View Statusbar");

CheckMenuItem小部件已创建。

stat.Toggle();

Toggle()方法选中/取消选中检查菜单项。

if (item.Active) {
    statusbar.Show();
} else {
    statusbar.Hide();
}

根据CheckMenuItem的状态,我们显示或隐藏状态栏小部件。

图:CheckMenuItem

子菜单

我们的最后一个示例演示了如何在 GTK# 中创建一个子菜单。

submenu.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Submenu")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        MenuBar mb = new MenuBar();

        Menu filemenu = new Menu();
        MenuItem file = new MenuItem("File");
        file.Submenu = filemenu;

        // submenu creation
        Menu imenu = new Menu();

        MenuItem import = new MenuItem("Import");
        import.Submenu = imenu;

        MenuItem inews = new MenuItem("Import news feed...");
        MenuItem ibookmarks = new MenuItem("Import bookmarks...");
        MenuItem imail = new MenuItem("Import mail...");

        imenu.Append(inews);
        imenu.Append(ibookmarks);
        imenu.Append(imail);

        // exit menu item
        MenuItem exit = new MenuItem("Exit");
        exit.Activated += OnActivated;

        filemenu.Append(import);
        filemenu.Append(exit);
        mb.Append(file);

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(mb, false, false, 0);
        vbox.PackStart(new Label(), false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnActivated(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

子菜单创建。

Menu imenu = new Menu();

子菜单是Menu

MenuItem import = new MenuItem("Import");
import.Submenu = imenu;

它是菜单项的子菜单,它会登录到顶级文件菜单。

MenuItem inews = new MenuItem("Import news feed...");
MenuItem ibookmarks = new MenuItem("Import bookmarks...");
MenuItem imail = new MenuItem("Import mail...");

imenu.Append(inews);
imenu.Append(ibookmarks);
imenu.Append(imail);

子菜单有其自己的菜单项。

图:子菜单

在 GTK# 编程库的这一章中,我们展示了如何使用菜单。

GTK# 中的工具栏

原文: http://zetcode/gui/gtksharp/toolbars/

在 GTK# 编程教程的这一部分中,我们将使用工具栏。

菜单将我们可以在应用中使用的命令分组。 使用工具栏可以快速访问最常用的命令。 工具栏是带有按钮的水平或垂直面板。 这些按钮包含图像或图像和文本。 通过单击工具栏按钮,我们执行一个动作。

简单的工具栏

接下来,我们创建一个简单的工具栏。

toolbar.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Toolbar")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        Toolbar toolbar = new Toolbar();
        toolbar.ToolbarStyle = ToolbarStyle.Icons;

        ToolButton newtb = new ToolButton(Stock.New);
        ToolButton opentb = new ToolButton(Stock.Open);
        ToolButton savetb = new ToolButton(Stock.Save);
        SeparatorToolItem sep = new SeparatorToolItem();
        ToolButton quittb = new ToolButton(Stock.Quit);

        toolbar.Insert(newtb, 0);
        toolbar.Insert(opentb, 1);
        toolbar.Insert(savetb, 2);
        toolbar.Insert(sep, 3);
        toolbar.Insert(quittb, 4);

        quittb.Clicked += OnClicked;

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(toolbar, false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnClicked(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

该示例显示了一个工具栏和四个工具按钮。

Toolbar toolbar = new Toolbar();

Toolbar小部件已创建。

toolbar.ToolbarStyle = ToolbarStyle.Icons;

在工具栏上,我们仅显示图标。 没有文字。

ToolButton newtb = new ToolButton(Stock.New);

创建带有库存图像的ToolButton

SeparatorToolItem sep = new SeparatorToolItem(); 

这是一个分隔符。 它可用于将工具栏按钮分组为逻辑组。

toolbar.Insert(newtb, 0);
toolbar.Insert(opentb, 1);
...

工具栏按钮插入到工具栏小部件中。

图:工具栏

工具栏

在第二个示例中,我们显示了两个工具栏。 许多应用具有多个工具栏。 我们展示了如何在 GTK# 中做到这一点。

toolbars.cs

using Gtk;
using System;

class SharpApp : Window {

    public SharpApp() : base("Toolbars")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        Toolbar upper = new Toolbar();
        upper.ToolbarStyle = ToolbarStyle.Icons;

        ToolButton newtb = new ToolButton(Stock.New);
        ToolButton opentb = new ToolButton(Stock.Open);
        ToolButton savetb = new ToolButton(Stock.Save);

        upper.Insert(newtb, 0);
        upper.Insert(opentb, 1);
        upper.Insert(savetb, 2);

        Toolbar lower = new Toolbar();
        lower.ToolbarStyle = ToolbarStyle.Icons;

        ToolButton quittb = new ToolButton(Stock.Quit);
        quittb.Clicked += OnClicked;
        lower.Insert(quittb, 0);

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(upper, false, false, 0);
        vbox.PackStart(lower, false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnClicked(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

我们的应用显示了两个工具栏。

Toolbar upper = new Toolbar();
...
Toolbar lower = new Toolbar();

我们创建两个Toolbar小部件。

upper.Insert(newtb, 0);
...
lower.Insert(quittb, 0);

它们每个都有自己的工具按钮。

VBox vbox = new VBox(false, 2);
vbox.PackStart(upper, false, false, 0);
vbox.PackStart(lower, false, false, 0)

工具栏一个接一个地包装在垂直盒中。

图:工具栏 s

撤销重做

以下示例演示了如何停用工具栏上的工具栏按钮。 这是 GUI 编程中的常见做法。 例如,保存按钮。 如果我们将文档的所有更改都保存到磁盘上,则在大多数文本编辑器中,“保存”按钮将被禁用。 这样,应用会向用户指示所有更改都已保存。

undoredo.cs

using Gtk;
using System;

class SharpApp : Window {

    private int count = 2;
    private ToolButton undo;
    private ToolButton redo;

    public SharpApp() : base("Undo redo")
    {
        SetDefaultSize(250, 200);
        SetPosition(WindowPosition.Center);
        DeleteEvent += delegate { Application.Quit(); };

        Toolbar toolbar = new Toolbar();
        toolbar.ToolbarStyle = ToolbarStyle.Icons;

        undo = new ToolButton(Stock.Undo);
        redo = new ToolButton(Stock.Redo);
        SeparatorToolItem sep = new SeparatorToolItem();
        ToolButton quit = new ToolButton(Stock.Quit);

        toolbar.Insert(undo, 0);
        toolbar.Insert(redo, 1);
        toolbar.Insert(sep, 2);
        toolbar.Insert(quit, 3);

        undo.Clicked += OnUndo;
        redo.Clicked += OnRedo;
        quit.Clicked += OnClicked;

        VBox vbox = new VBox(false, 2);
        vbox.PackStart(toolbar, false, false, 0);
        vbox.PackStart(new Label(), false, false, 0);

        Add(vbox);

        ShowAll();
    }

    void OnUndo(object sender, EventArgs args)
    {
        count -= 1;

        if (count <= 0) {
            undo.Sensitive = false;
            redo.Sensitive = true;
        }
    }

    void OnRedo(object sender, EventArgs args)
    {
        count += 1;

        if (count >= 5) {
            redo.Sensitive = false;
            undo.Sensitive = true;
        }
    }

    void OnClicked(object sender, EventArgs args)
    {
        Application.Quit();
    }

    public static void Main()
    {
        Application.Init();
        new SharpApp();
        Application.Run();
    }
}

我们的示例从 GTK# 库存资源创建撤消和重做按钮。 单击几下后,每个按钮均被禁用。 按钮显示为灰色。

private int count = 2;

计数变量决定哪个按钮被激活和禁用。

undo = new ToolButton(Stock.Undo);
redo = new ToolButton(Stock.Redo);

我们有两个工具按钮。 撤消和重做工具按钮。 图片来自库存资源。

undo.Clicked += OnUndo;
redo.Clicked += OnRedo;

我们为两个工具按钮都插入了Clicked事件的方法。

if (count <= 0) {
    undo.Sensitive = false;
    redo.Sensitive = true;
}

要激活小部件,我们将其Sensitive属性设置为 true。 要使其无效,我们将其设置为false

图:撤销和重做

在 GTK# 编程库的这一章中,我们提到了工具栏。

发布者:admin,转转请注明出处:http://www.yc00.com/web/1754948120a5219466.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信