Разработка диалогов

From FreeCAD Documentation
Revision as of 12:30, 2 August 2011 by Psi13art (talk | contribs)

На этой странице мы покажем как создать простой Qt Dialog с помощью Qt Designer, это официальный Qt инструмент для создания интерфейсов, затем сковертировать его в python код, ф затем использовать внутри FreeCAD. Я буде полагать в этом примере, что вы уже знаете как редактировать и запускать сценарии на python, и конечно что вы можете делать просты действия в окне терминала такие как навигация и.т.д. Конечно, у вас также должен быть установлен pyqt.

Проектирование диалога

В CAD приложения, очень важно, проектирование хорошего UI (User Interface/Пользовательского Интерфейса). Обо все что будет делать пользователь через части интерфейса: чтение диалоговых окон, нажатие кнопок, выбор между иконками, и.т.д. Так что очень важно тщательно подумать, что вы хотите сделать, как вы хотите чтобы пользователь повел себя и как будут работать ваши действия

Известно несколько понятий, от том как проектировать интерфейс:

  • Modal/non-modal dialogs: Модальное окно появляется поверх всех окон, останавливая действия происходящие в главном окне приложения, заставляя пользователя отвечать в диалоговом окне, тогда как не модальный диалог не останавливает вас от работы в главном окне. В некоторых случаях лучше первое, в других нет.
  • Определение того, что требуется и что считается дополнительны: Убедитесь что пользователь знает что он должен делать. Ставте на все метки с описанием, используйте подсказки, и.т.д.
  • Отделяйте команды от параметров: Это обычно делается с помощью кнопок и полей текстовых ввода. Пользователь знает что нажатие кнопки будет производить действие тогда как изменение значения внутри текстового поля где-то будет изменять параметр. В настоящие время, однако, пользователи обычно отлично знают что есть кнопка, а что есть поле ввода, и.т.д. В качестве графического инструментария используется, Qt, это современный инструментарий, и мы не должны больш беспокоится о создании ясности, так как он уже сам по себе очень ясный/понятный интерфейс.

Таким образом, теперь когда мы четко определили что должны делать, откройте qt designer. Давайте спроектируем очень простой диалог, как здесь:

Мы будем использовать этот диалог в FreeCAD для создания хороших прямоугольных плоскосте. Вам может показаться что это не очень удобно для создания прямоугольных плоскосте, но его легко можно изменить позже, чтобы делать более сложные вещи. Когда вы откроете Qt Designer, он выглядит следующим образом:

Он очень прост в использовании. На левой панели есть элименты которые можно перетащить на ваш виджет. На правой стороне находится панель свойств отображающая все виды редактируемых свойств, выбранного элемента. Так что начните с создания нового виджета. Выберете "Диалог без кнопок", так как мы не хотим кнопки по умолчанию Ok/Cancel. Затем, перетащите на ваш виджет 3 этикетки(labels), одна для заголовка, одно для надписи "Height" и одна для записи "Width". Этикетки это просто тексты которые появляются на вашем виджете, чтобы проинформировать пользователя. Если вы выбираете этикетку, на правой стороне появляются свойства которые вы можете поменять, если вы хотите, такие как стиль шрифта, высота и.т.д.

Затем, добавте 2 LineEdits, которые представляют собой текстовые поля которые пользователь может заполнить, одно для высоты(height) и одно для ширины(width). Здесь также, можно редактировать свойства. Например, почему не задать значение по умолчанию? Например по 1.00 для каждого. Таким образом, когда пользователь увидет диалоговое окно, боа значения будут уже введены и если его они удовлетворяют , он ожет сразу нажать на кнопку, сохранив драгоценное время. Потом, добавим PushButton, которую кнопку необходимо нажать после тогокакон заполнит оба поля.

Обратите внимание что здесь я выбрал очень просто управление, но в Qt гораздо больше функций, например, например вы можете использовать Spinboxes вместо LineEdits, и.т.д... Обратите внимание на то что доступно, у вас несомнено появятся другие идеи.

Вот и все, что мы должны сделать в Qt Designer. Последнее, давайте переименуем все наши элементы дав им более простые имена, так что будет легче определять их в нашем сценарии:

Конвертация нашего диалога в python

Теперь сохраните ваш виджет где-нибудь. Он будет сохранен как .ui файл, который мы легко преобразуем в python сценарий с помощью pyuic. В windows, программа pyuic связанна с pyqt (должно быть проверено), на linux вам вероятно нужно будет установить его отдельно в вашем пакетном менеджере (для debian-based систем, это часть пакета pyqt4-dev-tools). Для преобразования, вам необходимо открыть окно терминала (или окно командной строки в windows), переместитесь туда где вы сохранили ваш .ui файл и введите:

pyuic mywidget.ui > mywidget.py

На некоторых системах вызвайте pyuic4 вместо pyuic. Просто сконвертируйте .ui файл в python сценарий. Если вы откроем файл mywidget.py , его содержание очень легко понять:

from PyQt4 import QtCore, QtGui

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(187, 178)
        self.title = QtGui.QLabel(Dialog)
        self.title.setGeometry(QtCore.QRect(10, 10, 271, 16))
        self.title.setObjectName("title")
        self.label_width = QtGui.QLabel(Dialog)
        ...

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

   def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
        self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8))
        ...

Как вы видете, он обладает очень простым устройством: созданный класс называемый Ui_Dialog, он содержит все элементы интерфейса нашего виджета. Этот класс обладает двумя методами, один для создания виджета, и одни для перевода его содержания, эта часть является основным Qt механизмом для перевода элементов интерфейса. Метод установки(setup method) просто создает один за другим, виджетв так как мы задали их в Qt Designer, и задает их настройки так как мы определили ранее. Затем, весь инструмент будет переведен, и наконец, подключаются слоты (мы поговорим об этом позже).

Теперь мы можем создать новый виджет и использовать этот класс для созданияего интерфейса. Мы уже можем увидеть наш виджет в действии, поместив наш файл mywidget.py в место где FreeCAD сможет найти его (в FreeCAD в паку bin, или в любую Mod поддеерикторию) ,и ввести в FreeCAD python интепритатор:

from PyQt4 import QtGui
import mywidget
d = QtGui.QWidget()
d.ui = mywidget.Ui_Dialog()
d.ui.setupUi(d)
d.show()

И наш диалог появится! Заметим, что наш интерпритатор по прежнему работает, т.е у нас не модальный диалог. Так что, закроем его, мы можеи (конечно, помимо того как щелкнуть на иконке закрытия) ввести:

d.hide()

делаем так чтобы наш диалог делал что-нибудь

Теперь когда мы можем показать или скрыть наш диалог, на осталось добавить последнюю часть:Чтобы оно что-то делало! Если вы немного поиграетесь с Qt designer, вы быстро обнаружите целый раздел под название "сигналы и слоты". В основном, это работает следующим образом: элемент на вашем виджете (в Qt терминалогии, эти элементы сами по себе являются виджетами) может отправить сигнал. Этот сигнал отличаются в зависимости от типа виджета. Например, кнопка может подать сигнал при нажатии, и когда она будет отпущена. Этот сигнал может быть соединен со слотами, которые могут быть специальными функциями других виджетов(например диалог обладающий слотом "закрыть" который можно подключить к сигналу от кнопки закрытия), или это могут быть пользовательские функции. PyQt Reference Documentation список всех qt виджетов, что они делают, какие сигналы могут отправлять и.т.д...

Что мы будем делать здесь, создадим новую функцию , которая создает плоскость основываясь на её длине и ширине, и подключим эту функцию к сигналу нажатия испускаемому нашей кнопкой "Create!" . Так что , давайте начнем с импорта наших модулейr FreeCAD, палагая следующую строку введенной в начале нашего сценария, где мы уже импортировали QtCore и QtGui:

import FreeCAD, Part

Затем , давайте добавим новую функцию в наш класс Ui_Dialog:

def createPlane(self):
    try:
        # first we check if valid numbers have been entered
        w = float(self.width.text())
        h = float(self.height.text())
    except ValueError:
        print "Error! Width and Height values must be valid numbers!"
    else:
        # create a face from 4 points
        p1 = FreeCAD.Vector(0,0,0)
        p2 = FreeCAD.Vector(w,0,0)
        p3 = FreeCAD.Vector(w,h,0)
        p4 = FreeCAD.Vector(0,h,0)
        pointslist = [p1,p2,p3,p4,p1]
        mywire = Part.makePolygon(pointslist)
        myface = Part.Face(mywire)
        Part.show(myface)
        self.hide()

Потом, нам нужно сообщить Qt о подключении функции к кнопке, разместив следующую строчку перед QtCore.QMetaObject.connectSlotsByName(Dialog):

QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed()"),self.createPlane)

как вы видете, подключение сигнала pressed() от нашего созданного объекта (кнопка "Create!"), к слоту названому createPlane, который мы только что определили. И это всё!!Теперь,финальный штрих, мы можем добавить маленькую функцию в создание диалога, его легче будет вызвать. Вне класса Ui_Dialog, давайте добавим этот код:

class plane():
    d = QtGui.QWidget()
    d.ui = Ui_Dialog()
    d.ui.setupUi(d)
    d.show()

Затем , в FreeCAD, нам необходимо сделать только:

import mywidget
mywidget.plane()

"Это все ребята"... Теперь вы можете попробовать разные вещи, например как вставить ваш виджет в FreeCAD интерфейс (смотри страницу Отрывки кода ), или создать более продвинутый пользовательский инструмент, используя другие элементы в вашем виджете.

Готовый сценарий

Это полный сценарий, для справки:

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

# Form implementation generated from reading ui file 'mywidget.ui'
#
# Created: Mon Jun  1 19:09:10 2009
#      by: PyQt4 UI code generator 4.4.4
#
# WARNING! All changes made in this file will be lost!

from PyQt4 import QtCore, QtGui
import FreeCAD, Part 

class Ui_Dialog(object):
   def setupUi(self, Dialog):
       Dialog.setObjectName("Dialog")
       Dialog.resize(187, 178)
       self.title = QtGui.QLabel(Dialog)
       self.title.setGeometry(QtCore.QRect(10, 10, 271, 16))
       self.title.setObjectName("title")
       self.label_width = QtGui.QLabel(Dialog)
       self.label_width.setGeometry(QtCore.QRect(10, 50, 57, 16))
       self.label_width.setObjectName("label_width")
       self.label_height = QtGui.QLabel(Dialog)
       self.label_height.setGeometry(QtCore.QRect(10, 90, 57, 16))
       self.label_height.setObjectName("label_height")
       self.width = QtGui.QLineEdit(Dialog)
       self.width.setGeometry(QtCore.QRect(60, 40, 111, 26))
       self.width.setObjectName("width")
       self.height = QtGui.QLineEdit(Dialog)
       self.height.setGeometry(QtCore.QRect(60, 80, 111, 26))
       self.height.setObjectName("height")
       self.create = QtGui.QPushButton(Dialog)
       self.create.setGeometry(QtCore.QRect(50, 140, 83, 26))
       self.create.setObjectName("create")

       self.retranslateUi(Dialog)
       QtCore.QObject.connect(self.create,QtCore.SIGNAL("pressed()"),self.createPlane)
       QtCore.QMetaObject.connectSlotsByName(Dialog)

   def retranslateUi(self, Dialog):
       Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
       self.title.setText(QtGui.QApplication.translate("Dialog", "Plane-O-Matic", None, QtGui.QApplication.UnicodeUTF8))
       self.label_width.setText(QtGui.QApplication.translate("Dialog", "Width", None, QtGui.QApplication.UnicodeUTF8))
       self.label_height.setText(QtGui.QApplication.translate("Dialog", "Height", None, QtGui.QApplication.UnicodeUTF8))
       self.create.setText(QtGui.QApplication.translate("Dialog", "Create!", None, QtGui.QApplication.UnicodeUTF8))

   def createPlane(self):
       try:
           # first we check if valid numbers have been entered
           w = float(self.width.text())
           h = float(self.height.text())
       except ValueError:
           print "Error! Width and Height values must be valid numbers!"
       else:
           # create a face from 4 points
           p1 = FreeCAD.Vector(0,0,0)
           p2 = FreeCAD.Vector(w,0,0)
           p3 = FreeCAD.Vector(w,h,0)
           p4 = FreeCAD.Vector(0,h,0)
           pointslist = [p1,p2,p3,p4,p1]
           mywire = Part.makePolygon(pointslist)
           myface = Part.Face(mywire)
           Part.show(myface)

class plane():
    d = QtGui.QWidget()
    d.ui = Ui_Dialog()
    d.ui.setupUi(d)
    d.show()


Line drawing function/ru
License/ru
Available translations of this page: Template:Se