Модераторы: pythonwin, Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Программирование с PyQt4 
:(
    Опции темы
Artemios
Дата 15.6.2007, 20:22 (ссылка) |    (голосов:12) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Воодушевленный примером GrayCardinal, решил продолжить введение в Qt4, но на новых "рельсах", а именно Python+PyQt4.

Программирование на Python с использованием PyQt4

Установка.

Так как PyQt - привязка библиотеки Qt к Python-у, то в первую очередь нам требуется наличие самой Qt 4.x.

Под Linux большинство дистрибутивов включают Qt4 в стандартную поставку, при отсутствии же можно поискать в соответствующих для данной системы репозитариях. Альтернативный вариант: скачать с Trolltech-а исходники и собрать библиотеку самому. В последнем случае у меня проблем не возникало, стандартная последовательность действий:
./configure
make
sudo make install
ну и при желании в configure задать нужные ключи.

ОС Windows. Для сей операционной системы существуют варианты Qt4 под разные компиляторы, но свободной лицензией (GPL) обладает только Qt для компилятора MinGW (это реализация GNU C/C++ под Windows). Поэтому, в первую очередь качаем и ставим MinGW, в системной переменной PATH прописываем путь до директории MinGW/bin. Далее можно с Trolltech-а скачать либо исходники последней версии Qt и собрать самому (под Win я этим не занимался, поэтому здесь не советчик), либо скачать и поставить уже откомпилированную библиотеку.

Итак, мы являемся счастливыми обладателями Qt4 и на C++ уже можем ваять, но мы любим Python. Сие предполагает, что в нашей системе уже установлен интерпретатор Python-а, и нам осталось только воткнуть в него привязку PyQt4.

ОС Linux. Пока что PyQt для Qt4 предустановленной видел только в Sabayon Linux, в других линуксах (правда я их совсем не много видел) либо вообще не находил пакетов с PyQt, либо была привязка PyQt к старой библиотеке Qt3 (хотя сейчас ситуация может уже улучшилась). Итак, будем собирать из исходников (фраза не для пользователей Gentoo smile ). Для этого во-первых необходимо, чтобы в нашей операционной системе кроме собственно Python-а были еще поставлены его dev-пакеты (пакеты для разработчика). Ну или альтернативный вариант: Python также собран из исходников smile
Последовательность действий:
качаем от разработчика исходники последней версии SIP
- распаковываем
- python ./configure.py
- make
- sudo make install
качаем от разработчика исходники последней версии PyQt4
- распаковываем
- python ./configure.py
- make
- sudo make install

ОС Windows. На данный момент мы уже имеем MinGW, Qt4, Python. Качаем от разработчика уже собранную под win32 последнюю версию PyQt4, ставим, радуемся жизни.


Привет мир.

Итак, мы уже имеем рабочий вариант PyQt4 и дальнейшие наши программы не зависят от конкретной системы, одинаково запускаясь везде, где есть PyQt. В Qt имеется симпатичный набор примеров на C++ по использованию библиотеки, и в PyQt те же примеры переписаны на Python-е (еще одна демонстрация лаконичности и красоты синтаксиса Python при использовании идентичных классов/методов/объектов). Плюс обширная документация Qt по всем классам, и почти зеркальное ее отражение в документации по PyQt - все это существенным образом уменьшает ценность моих здесь стараний, но я продолжу.

Самый элементарный пример, демонстрирующий создание приложения Qt и вывод окна на экран:
Код

# импортируем необходимые модули:
import sys
from PyQt4 import QtGui

if __name__=="__main__":
    # создаем объект Qt-приложения, передаем его конструктору
    # параметры командной строки:
    app = QtGui.QApplication(sys.argv)
    # создаем объект класса QLabel (метка), в конструкторе задаем подпись для метки:
    label = QtGui.QLabel("Hello World!\n\tThis is the very simple example for PyQt4.")
    # показываем метку:
    label.show()
    # запускаем цикл обработки событий, происходящих с элементами приложения:
    sys.exit(app.exec_())

После запуска программы (в консоли линукса $ python ./helloworld01.py ,в windows можно двойным кликом мыши по *.py файлу) увидим такое окошко:
user posted image
Заметим, что здесь мы не создавали отдельно окно, как контейнер для метки. Любой графический объект Qt - это виджет (и наследуется от QWidget), и если он не привязан к какому-либо контейнеру, то отображается в отдельном окошке.

Если мы хотим использовать русские подписи, то простейшим вариантом будет использование юникода (префикс u перед записью строки):
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    label = QtGui.QLabel(u"Привет мир!\n\tЭто простейший пример для PyQt4.")
    label.show()
    sys.exit(app.exec_())

user posted image
Итак, мы можем создавать элементарное окошко и даже задавать элементарное форматирование для надписей через escape-символы (например \n - новая строка, \t - табуляция). Qt позволяет на нашем примере построить и более красивое оформление через поддержку простых элементов HTML-форматирования:
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    label = QtGui.QLabel(u"""<center><h1>Привет мир!</h1></center>
        <h2>Это <i>простейший пример</i> для <font color=red>PyQt4</font>.</h2>""")
    label.show()
    sys.exit(app.exec_())

user posted image
и окно той же самой программы, запущенной без каких либо изменений в ОС Windows:
user posted image

(На самом деле, Qt поддерживает даже CSS для своих виджетов, но об этом позднее)

Сигналы/слоты - теория.
(раздел не обязателен для прочтения, но желателен, для лучшего понимания внутреннего механизма)

Qt реализует более правильную идеологию ООП, нежели иные виденные мной GUI-библиотеки. Что у нас в теории ООП (и даже лучше сказать, не ОО Программирования, а ОО Проектирования) сказано про взаимодействие объектов? Правильно, объекты посылают сообщения (сигналы), объекты принимают сообщения, объекты выполняют операции (методы) и меняют состояние (а также испускают новые сигналы) в зависимости от принятых сообщений. В языке C++ подобная идеология не была реализована в полной мере (по крайней мере до появления Boost.Signals), потому Qt представляет надстройку над синтаксисом C++. Отсюда следует необходимость использования специального препроцессора (moc) для Qt-программы, дабы получить компилирующийся C++ код. 
Язык же Python интерпретируемый, динамически типизируемый и легко расширяемый, что дает нам возможность избежать "мучений" с препроцессором. PyQt предоставляет расширение языка, позволяющее использовать механизм сигнал/слотов Qt как "родной" для Python-а.

Итак, объект может испускать произвольное количество сигналов.
Каждый сигнал имеет свою сигнатуру: имя сигнала и типы передаваемых этим сообщением (сигналом) данных.
Объект может принимать произвольное количество сообщений от других объектов.
Механизм принятия сообщения реализуется через соединение (connect).
В соединении участвуют: 
- объект, отсылающий сигнал;
- сигнал объекта-отправителя;
- объект, принимающий сигнал;
- метод объекта-приемника (слот), выполняемый при получении сигнала.
Сигнатура (порядок и типы) входных аргументов слота должна совпадать с сигнатурой передаваемых сигналом данных.
- Вместо слота последним участником соединения может быть сигнал объекта-приемника, который приемник испускает при получении сигнала от отправителя, сигнатура параметров сигналов естественно также должна совпадать.

С одним сигналом может быть соединено несколько слотов и/или сигналов.
Один слот может быть соединен с несколькими сигналами.
Одно и то же соединение можно создать в нескольких экземплярах, тогда один сигнал будет инициировать соответственно многократное выполнение слота либо многократную генерацию нового сигнала.

Все классы Qt являются наследниками класса QObject. Класс QObject в PyQt имеет метод connect, который и осуществляет соединение сигнал-слот или сигнал-сигнал. Также класс QObject имеет метод emit, генерирующий сигнал от объекта данного класса.
Пример:
Код

# -*- coding: utf-8 -*-
from PyQt4.QtCore import QObject, SIGNAL

class A:
    # метод, который будем использовать в качестве слота:
    def main_slot(self,text):
        print "Объектом класса A получено сообщение с текстом:",text

class B(QObject):
    def send_signal(self,text):
        print "Из объекта класса B отправляется сообщение с текстом:",text
        self.emit( SIGNAL("main_signal(PyQt_PyObject)"), text )

if __name__=="__main__":
    a = A()
    b = B()
    # а вот, собственно, и соединение (Источник,Сигнал,СлотПриемника):
    QObject.connect( b, SIGNAL("main_signal(PyQt_PyObject)"), a.main_slot )
    # и теперь пошлем сигнал:
    b.send_signal("Траляля")

и выполнение:
Цитата

$ python ./signals01.py
Из объекта класса B отправляется сообщение с текстом: Траляля
Объектом класса A получено сообщение с текстом: Траляля
$

Примечание: в Python-е любые функции (а соответственно, и методы) являются полноценными объектами 1-го класса (в Python-е вообще всё является объектом), поэтому неимеет смысла в соединении указывать отдельно объект-приемник и отдельно его слот (т.к. слот также является объектом и имеет ссылку на объект, для которого он выступает методом). Отсюда отличие синтаксиса соединения Python/PyQt от C++/Qt:
(Источник,Сигнал,СлотПриемника) для Python-а и (Источник,Сигнал,Приемник,Слот) для C++.
С тем же свойством Python-овских функций связано еще одно отличие: в качестве СлотаПриемника может выступать и простая функция, не являющаяся методом какого-либо класса (объект-приемник и слот в одном лице smile ).

Для совместимости же с откомпилированными методами (слотами) классов библиотеки Qt (которые написаны на C++ и соответственно не являются объектами 1-го класса) в PyQt оставлен и 4-х аргументный вариант соединения.

Варианты соединений между Qt-шными и Python-овскими сигналами и слотами для случая сигнала без параметров:
Код

QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("qtSig()"), pyFunction_trg )
QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("qtSig()"), pyObj_trg.pyMethod )
QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("qtSig()"), qtObj_trg, QtCore.SLOT("qtSlot()") )
QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("pySig"),   pyFunction_trg )
QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("pySig"),   pyObj_trg.pyMethod )
QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("pySig()"), qtObj_trg, QtCore.SLOT("qtSlot()") )

Здесь:
qtObj_src - объект-источник сигнала, является экземпляром класса-потомка класса QObject, наследование может быть как реализованное в Qt (C++), так и как наследование Python-класса от Qt-класса;
qtSig() - сигнал источника, определенный в Qt;
pySig() - сигнал источника, определенный в Python-е;
pyFunction_trg - приемник и слот в одном лице - произвольная Python-функция;
pyObj_trg и pyMethod - приемник и его слот - произвольный Python-объект и его метод
qtObj_trg - приемник, как и qtObj_src экземпляр потомка от QObject; qtSlot() - его слот, определенный в Qt

Разрыв соединения достигается использованием метода disconnect с теми же аргументами, что использовались для connect. Допишем в конце предыдущего примера после
Код

    b.send_signal("Траляля")

следующие строки: 
Код

    QObject.disconnect( b, SIGNAL("main_signal(PyQt_PyObject)"), a.main_slot )
    # а теперь сигнал будет послан, но никем не принят:
    b.send_signal("Ту-ту!")

и выполним программу:
Цитата

$ python ./signals02.py
Из объекта класса B отправляется сообщение с текстом: Траляля
Объектом класса A получено сообщение с текстом: Траляля
Из объекта класса B отправляется сообщение с текстом: Ту-ту!
$


Соединение вида сигнал-сигнал объявляется таким образом:
Код

QtCore.QObject.connect( qtObj_src, QtCore.SIGNAL("anySig1"), qtObj_trg, QtCore.SIGNAL("anySig2") )

где и источник, и "приемо-передатчик" - оба экземпляры C++ или Python потомков класса QObject,
anySig1 и anySig2 - произвольные сигналы (либо определенные в Qt, либо в Python-программе по месту использования).
Для примера построим последовательную цепь соединений вида
user posted image
Код

# -*- coding: utf-8 -*-
from PyQt4.QtCore import QObject, SIGNAL

class A:
    def main_slot(self):
        print "Объектом класса A получен сигнал"

class B(QObject):
    pass

class C(QObject):
    def send_signal(self):
        print "Из объекта класса C отправляется сигнал"
        self.emit(SIGNAL("signal01()"))

if __name__=="__main__":
    a = A()
    b = B()
    c = C()
    QObject.connect( c, SIGNAL("signal01()"), b, SIGNAL("signal02()") )
    QObject.connect( b, SIGNAL("signal02()"), a.main_slot )
    c.send_signal()

Цитата

$ python ./sig2sig.py
Из объекта класса C отправляется сигнал
Объектом класса A получен сигнал
$


Знакомым с программированием на Qt/C++ после приведенных примеров очевидно явное отличие. В Qt/C++ необходимо было методы, являющиеся слотами, описывать в отдельных секциях, public slots например, а если программист неудовлетворялся набором стандартных сигналов класса-предка, от которого он наследовался, то каждый новый сигнал описывался в секции signals . Препроцессор же потом переводил эти объявления в пригодные для компилирования конструкции языка C++. Следствием динамической типизации Python-а является не только то, что мы можем динамически назначить слотом произвольно выбранный метод/функцию или любой иной объект с методом __call__(), но и то, что динамически можем определять для объекта новые сигналы, о которых становится известно только на этапе выполнения connect.


Сигналы/слоты - GUI-шная практика.
На самом деле все не так страшно, как может показаться прочитавшему предыдущий раздел, и сейчас мы займемся вещами более наглядными smile

Все графические объекты библиотеки Qt имеют наборы сигналов, которые они испускают при при наступлении некоторых внешних (например клик мыши) либо внутренних (например таймер) событий. Кроме того, сигналы объектами испускаются при вызове методов, изменяющих состояние объектов. В данных, передаваемых сигналами, обычно содержится информация о произошедших изменениях в состоянии объекта. Проиллюстрируем на примерах.
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    button = QtGui.QPushButton(u"Выход")
    button.setFont( QtGui.QFont("Arial", 16, QtGui.QFont.Bold) )
    QtCore.QObject.connect( button, QtCore.SIGNAL("clicked()"), app, QtCore.SLOT("quit()") )
    button.show()
    sys.exit(app.exec_())

user posted image
Здесь, как видно, мы связали сигнал clicked() кнопки со слотом quit() объекта приложения, по названиям не трудно догадаться и о значении этих сигнала и слота. Связали не-Python-овские сигнал и слот, потому использована четырёхаргументная запись соединения.

Другой пример. Создадим в окне два расположенных горизонтально объекта: SpinBox и Slider (ползунок), с помощью которых мы будем выбирать свой возраст. Создадим между ними двустороннее соединение, то есть два соединения, при которых изменение одного объекта будет сразу автоматически изменять и другой объект. И добавим Python-овский слот для отображения изменений в консоли.
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui

class AgeSelector(QtGui.QWidget):
    def __init__(self,*args):
        QtGui.QWidget.__init__(self,*args)
        self.setWindowTitle(u"Вводим свой возраст")
        # создаем объекты:
        spinbox = QtGui.QSpinBox()
        slider = QtGui.QSlider(QtCore.Qt.Horizontal)
        # устанавливаем границы значений:
        spinbox.setRange(0, 130)
        slider.setRange(0, 130)
        # создаем соединения:
        self.connect(spinbox, QtCore.SIGNAL("valueChanged(int)"), \
                slider, QtCore.SLOT("setValue(int)"))
        self.connect(slider, QtCore.SIGNAL("valueChanged(int)"), \
                spinbox, QtCore.SLOT("setValue(int)"))
        self.connect(spinbox, QtCore.SIGNAL("valueChanged(int)"), self.log_to_console)
        # задаем начальное значение:
        spinbox.setValue(27)
        # создаем горизонтальное размещение объектов в окне:
        layout = QtGui.QHBoxLayout()
        layout.addWidget(spinbox)
        layout.addWidget(slider)
        self.setLayout(layout)
    # слот, пишущий лог изменений в консоль:
    def log_to_console(self,i):
        print i
        
if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    age_sel = AgeSelector()
    age_sel.show()
    sys.exit(app.exec_())

Имеем окно приложения:
user posted image
а при передвижении ползунка со значения 27 до значения 35 в консоли получим ряд:
Цитата

27
28
29
31
32
33
34
35


Коль скоро мы затронули взаиморасположение объектов в окне, то следующий раздел этому и посвятим:

Геометрия/размещения



Это сообщение отредактировал(а) Artemios - 20.6.2007, 02:56


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Artemios
Дата 17.6.2007, 23:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Геометрия/размещение.

Чтобы разместить один виджет в другом, мы могли бы и не указывать каких-либо особенностей размещения, лишь передать конструктору размещаемого виджета ссылку на виджет-контейнер в качестве необязательного аргумента parent конструктора (смотрим документацию Qt4/PyQt4 по классам). Например, кнопка в окошко могла бы быть помещена так:
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui

class AnyWidget(QtGui.QWidget):
    def __init__(self,*args):
        QtGui.QWidget.__init__(self,*args)
        button = QtGui.QPushButton(u"Кнопка",self)

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    aw = AnyWidget()
    aw.show()
    sys.exit(app.exec_())

user posted image
Однако, если бы мы захотели добавить таким же образом на parent-виджет еще один графический объект, то он разместился бы поверх предыдущего объекта, целиком или полностью его перекрывая. Некрасивый и не рекомендуемый метод разрешения подобной ситуации - "в ручную" задавать геометрическое положение объектов в контейнере, используя метод setGeometry(x, y, width, height). Допишем в предыдущий пример в конструктор класса AnyWidget следующие строки:
Код

        button2 = QtGui.QPushButton(u"Кнопка2",self)
        button.setGeometry(5, 5, 100, 20)
        button2.setGeometry(110, 5, 100, 20)

user posted image
Очевидный недостаток такого подхода проявится сразу же, как только мы начнем менять размеры окна:
user posted image
Здесь можно было бы придумать различные пути обхода такого поведения окна: либо запретить изменение размеров, либо динамически пересчитывать положение элементов в контейнере при каждом изменении. 
Однако большинство GUI-библиотек, в том числе и Qt, предоставляют более гибкие и совершенные механизмы размещения графических объектов в контейнере. В Qt для этих целей существуют менеджеры размещения, наследуемые от класса QLayout. 

Рассмотрим три основных менеджера размещений: QHBoxLayout, QVBoxLayout и QGridLayout. Для размещения объектов в один ряд по горизонтали используем QHBoxLayout, аналогично QVBoxLayout для размещения объектов по вертикали:
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui

class AnyWidget(QtGui.QWidget):
    def __init__(self,*args):
        QtGui.QWidget.__init__(self,*args)
        button1 = QtGui.QPushButton(u"Кнопка1")
        button2 = QtGui.QPushButton(u"Кнопка2")
        layout = QtGui.QVBoxLayout(self)
        layout.addWidget(button1)
        layout.addWidget(button2)

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    aw = AnyWidget()
    aw.show()
    sys.exit(app.exec_())

user posted image

Для более сложных размещений используют QGridLayout, а также комбинации из всех трех менеджеров (для добавления подчиненного виджета - метод addWidget, для добавления подчиненного менеджера размещений - метод addLayout). QGridLayout размещает добавляемые элементы в ячейках воображаемой таблицы, причем каждый элемент может занимать несколько смежных ячеек по вертикали и/или горизонтали.
Запись метода addWidget для класса QGridLayout (addLayout имеет аналогичную форму):
Код

addWidget(widget, row, col) # размещение элемента в одной ячейке
addWidget(widget, from_row, from_col, row_span, col_span) # размещение элемента в нескольких ячейках


Проиллюстрируем комбинированное использование на примере с множеством объектов.
Код

# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtCore, QtGui

class AnyWidget(QtGui.QWidget):
    def __init__(self,*args):
        QtGui.QWidget.__init__(self,*args)
        boxlay = QtGui.QHBoxLayout(self)

        frame = QtGui.QFrame(self) # Фрейм
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setFrameShadow(QtGui.QFrame.Raised)
        
        gridlay = QtGui.QGridLayout(frame) # Менеджер размещения элементов во фрейме
        
        label = QtGui.QLabel(u"Метка",frame) # Текстовая метка.
        gridlay.addWidget(label,0,0)
        
        ln_edit = QtGui.QLineEdit(u"Винни Пух", frame) # Строковое поле ввода.
        gridlay.addWidget(ln_edit,0,1)
        
        radio_group = QtGui.QGroupBox(u"Выбор из двух", frame) # Рамка с надписью вокруг группы элементов.
        radio_lay = QtGui.QVBoxLayout(radio_group)             # Менеджер размещения элементов в рамке.
        radio1 = QtGui.QRadioButton(u"Первый", radio_group) # Два зависимых
        radio2 = QtGui.QRadioButton(u"Второй", radio_group) # переключателя
        radio2.setChecked(True)
        radio_lay.addWidget(radio1)
        radio_lay.addWidget(radio2)
        gridlay.addWidget(radio_group,1,0,3,1)
        
        combo = QtGui.QComboBox(frame) # Поле ввода с раскрывающимся списком.
        combo.addItem(u"Пятачок")
        combo.setEditable(True)
        gridlay.addWidget(combo,1,1)
        
        spin = QtGui.QSpinBox(frame) # Целочисленное поле ввода с
        spin.setValue(5)             # кнопками инкремента/декремента.
        gridlay.addWidget(spin,2,1)
        
        check = QtGui.QCheckBox(u"Пометка", frame) # Независимый переключатель с
        check.setCheckState(QtCore.Qt.Checked)     # двумя состояниями.
        gridlay.addWidget(check,3,1)
        
        progress = QtGui.QProgressBar(frame) # индикатор прогресса
        progress.setValue(70)
        progress.setOrientation(QtCore.Qt.Horizontal)
        gridlay.addWidget(progress,4,0,1,2)
        
        btn_lay = QtGui.QHBoxLayout() # Менеджер размещения двух кнопок.
        button1 = QtGui.QPushButton(u"Ок", frame)
        button2 = QtGui.QPushButton(u"Отмена", frame)
        btn_lay.addWidget(button1)
        btn_lay.addWidget(button2)
        gridlay.addLayout(btn_lay,5,0,1,2)
        
        boxlay.addWidget(frame)

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    aw = AnyWidget()
    aw.show()
    sys.exit(app.exec_())

user posted image

Если нас не удовлетворяет то, как ведут себя какие-либо элементы при изменении размеров окна, то можно попытаться вызвать для них метод setSizePolicy, первый параметр которого задает политику изменения ширины элемента, а второй - его высоты. Каждый параметр может принимать одно из значений:
  •  QtGui.QSizePolicy.Fixed - размер элемента в данном направлении не изменяется;
  •  QtGui.QSizePolicy.Minimum - "идеальным" размером элемента считается его минимальный размер. Элемент может растягиваться, но не может сжиматься;
  •  QtGui.QSizePolicy.Maximum - "идеальным" размером элемента считается его максимальный размер. Элемент может сжиматься, но не может растягиваться;
  •  QtGui.QSizePolicy.Preferred - элемент "старается" поддерживать некоторый предпочтительный для него размер, но при необходимости может растянуться или сжаться;
  •  QtGui.QSizePolicy.Expanding - элемент "старается" принять максимально возможный доступный ему размер, но при необходимости может и сжиматься.
Как видим, продумывание визуального взаиморасположения графических элементов в окне может быть занятием весьма утомительным. Однако в нашем распоряжении есть Qt Designer - WYSIWYG построитель графического иннтерфейса Qt, с которым создание очередного менеджера расположений с включёнными в него элементами сводится к одному-двум кликам мыши. 

Но прежде, чем мы перейдем к изучению Designer-а, рассмотрим на последнем примере использование различных стилей отображения визуальных элементов.



Это сообщение отредактировал(а) Artemios - 20.6.2007, 03:00


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Artemios
Дата 19.6.2007, 02:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Стили.

Qt поддерживает несколько предопределенных стилей (тем) для отображения своих виджетов. Доступные в библиотеке Qt для любой операционной системы стили: Windows, Motif, CDE, Plastique, Cleanlooks. Для пользователей ОС Windows XP доступен еще один стиль - WindowsXP, а для пользователей ОС Mac OS X - стиль Macintosh. Два последних стиля доступны (и используются по умолчанию) только на соответствующих ОС-х, так как в них организованы обертки над соответствующими системными API/движками стилей.

Задать предопределенный стиль отображения можно, и не производя каких-либо внутренних изменений в программе, лишь передавая в аргументах командной строки при запуске ключ -style=ИмяСтиля. Посмотрим, как будет отображаться в различных стилях последний пример предыдущего раздела.
user posted image
user posted image
Того же эффекта можно добиться, явно задавая в программе используемый стиль методом setStyle("ИмяСтиля"), вызывая его либо для объекта приложения (изменения вступят в силу для всех виджетов программы), либо для отдельно выбранного виджета.

Вообще, при программировании на Qt/C++ можно создавать классы со своими собственными стилями, наследуясь от предопределенных (соответствующие стилям классы - QИмястиляStyle, например QPlastiqueStyle). Однако в PyQt4 (по крайней мере, в версии PyQt 4.2) не включены Python-обертки для этих C++ классов. И сделано это, как я думаю, вполне оправданно, так как нет смысла строить свои классы стилей ввиду наличия в Qt более простого и удобного механизма построения собственных стилей: Qt Style Sheets - концепция, терминология и синтаксис которых аналогичны CSS для HTML.

Qt Style Sheets

Разжигая аппетит читателя, прежде чем давать какие-либо объяснения, приведу возможно не очень удачный с точки зрения дизайнера, но достаточно выразительный пример.

Сохраним в файл mystyle01.qss следующий CSS-подобный код:
Код

QWidget {
   background-color: beige;
}

QLineEdit, QFrame, QGroupBox, QPushButton {
    border-width: 2px;
    border-style: solid;
    border-color: darkkhaki;
    border-radius: 5px;
}

QPushButton {
    background-color: palegoldenrod;
}

QPushButton:hover {
   background-color: khaki;
}

QPushButton:pressed {
    padding-left: 2px;
    padding-top: 3px;
    background-color: #d0d67c;
}

QLabel, QAbstractButton {
    font: bold;
}

QComboBox, QLineEdit, QSpinBox {
    background-color: cornsilk;
}

QGroupBox::title {
    top: -4px;
}

и добавим в последний пример предыдущего раздела после строки
Код

    app = QtGui.QApplication(sys.argv)

следующую строку:
Код

    app.setStyleSheet(open("./mystyle01.qss","r").read())

При запуске получившейся программы будем иметь такое окошко:
user posted image

Продолжение следует.



Это сообщение отредактировал(а) Artemios - 21.6.2007, 03:13


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Artemios
Дата 21.6.2007, 03:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Развитие предыдущего примера.

Нарисуем и положим в директорию ./img такие примитивы:
user posted image
Сохраним в файл mystyle.qss следующий код:
Код

QWidget {
    color: black;
    background-color: beige;
    selection-color: white;
    selection-background-color: darkred;
}
QFrame, QLineEdit, QComboBox, QGroupBox, QAbstractSpinBox {
    border-width: 2px;
    border-style: solid;
    border-color: darkkhaki;
    border-radius: 5px;
}
QAbstractButton, QLabel {
    font: bold;
}
QComboBox, QLineEdit, QAbstractSpinBox {
    background-color: cornsilk;
}
QGroupBox {
    padding-top: 5px;
}
QGroupBox::title {
    padding-right: 5px;
    top: -4px;
}
QRadioButton::indicator::checked {
    image: url(./img/radio.png);
}
QRadioButton::indicator::checked:hover {
    image: url(./img/radio_hover.png);
}
QRadioButton::indicator::checked:pressed {
    image: url(./img/radio_pressed.png);
}
QRadioButton::indicator::unchecked,
QCheckBox::indicator:unchecked {
    image: url(./img/btn.png);
}
QRadioButton::indicator::unchecked:hover,
QCheckBox::indicator:unchecked:hover {
    image: url(./img/btn_hover.png);
}
QRadioButton::indicator::unchecked:pressed,
QCheckBox::indicator:unchecked:pressed {
    image: url(./img/btn_pressed.png);
}
QCheckBox::indicator:checked {
    image: url(./img/check.png);
}
QCheckBox::indicator:checked:hover {
    image: url(./img/check_hover.png);
}
QCheckBox::indicator:checked:pressed {
    image: url(./img/check_pressed.png);
}
*::down-arrow, *::menu-indicator {
    image: url(./img/down_arrow.png);
}
*::up-arrow {
    image: url(./img/up_arrow.png);
}
QComboBox {
    padding-right: 16px;
}
*::drop-down {
    subcontrol-origin: border;
    width: 13px;
    position: absolute;
    bottom: 1px;
}
QAbstractSpinBox { 
    padding-right: 15px;
}
*::up-button, *::drop-down {
    subcontrol-position: top right;
    top: 1px;
    right: 1px;
}
*::down-button {
    subcontrol-position: bottom right;
    bottom: 1px;
    right: 1px;
}
*::up-button, *::down-button {
    subcontrol-origin: border;
    width: 16px;
}
QPushButton, *::up-button,
*::down-button, *::drop-down {
    border-width: 4px;
    border-image: url(./img/btn.png);
}
QPushButton:hover, *::up-button:hover,
*::down-button:hover, *::drop-down:hover {
    border-image: url(./img/btn_hover.png) ;
}
QPushButton:pressed, *::up-button:pressed,
*::down-button:pressed, *::drop-down:on {
    border-image: url(./img/btn_pressed.png) ;
}
QPushButton:pressed {
    padding-left: 2px;
    padding-top: 1px;
}

и добавим в последний пример предыдущего раздела после строки
Код

    app = QtGui.QApplication(sys.argv)

следующие строки:
Код

    app.setStyle("Plastique")
    app.setStyleSheet(open("./mystyle.qss","r").read())

При запуске получившейся программы будем иметь такое окошко:
user posted image
Теперь любая программа на PyQt, к которой мы подобными строками подключим наше маленькое расширение стиля, будет выглядеть подобным образом.
Исходники приведенного примера присоединяю к сообщению.

Немножко теории. 
Qt Style Sheets - мощный механизм настройки внешнего стиля виджетов, выполненный, как я уже упоминал, в идеологии каскадных таблиц стилей (CSS). Используется как надстройка над основным заданным для виджетов стилем отображения (в приведенном выше примере в качестве основного был выбран Plastique).

Style Sheets состоит из последовательности стилевых правил. Стилевое правило состоит из селектора и декларации. Селектор определяет, к каким виджетам будет применяться текущее правило, в декларации задаются значения стилевых атрибутов выбранного виджета. Например правило:
Код

QAbstractButton { background-color : red }

задает красный цвет заднего фона для всех экземпляров классов-потомков класса QAbstractButton (например, QPushButton, QRadioButton). 
Несколько селекторов могут объединяться через запятую, например:
Код

QLineEdit, QComboBox { color: red }

Раздел декларации может содержать несколько пар вида атрибут:значение ,разделенных точкой с запятой:
Код

QPushButton { color: red; background-color: white }


Виды селекторов:
- Универсальный: * - сопоставляется со всеми виджетами.
- Селектор типа, например QPushButton - имя класса - сопоставляется с экземплярами данного класса и всех классов-потомков от данного.
- Атрибутный селектор: QPushButton[flat="false"] - сопоставляется только с теми экземплярами QPushButton, у которых на момент применения стиля значение атрибута flat равно false.
- Селектор класса: .QPushButton - точка перед именем класса - сопоставляется только с экземплярами данного класса, но не сопоставляется с экземплярами наследников от QPushButton.
- Селектор идентификатора: QPushButton#okButton - сопоставляется с экземпляром QPushButton, имеющем идентификатор "okButton" (каждому Qt-объекту можно задать идентификатор методом setObjectName; если мы строим форму при помощи Qt Designer-а, то у каждого виджета идентификатор будет задан автоматически в соответствии со свойством objectName в окне Property Editor)
- Селектор потомка: QDialog QPushButton - два класса, соединенные пробелом - сопоставляется со всеми экземплярами QPushButton, агрегированными в контейнере класса QDialog или в иных контейнерах, агрегированных в экземпляре QDialog (произвольной вложенности). (Следует заметить, что слово "потомок" здесь употребляется не в классическом понимании ООП, применительно к отношению наследования между классами, а применительно к отношению агрегации в контейнере, что ближе к терминологии XML/CSS)
- Селектор непосредственного потомка: QDialog > QPushButton - сопоставляется со всеми экземплярами QPushButton, являющимися непосредственными потомками (в смысле XML) экземпляра QDialog.

Кроме примитивных виджетов (кнопки, метки и т.д.), виждетов-агрегатов (контейнеров, напр. формы, фреймы, группирующие боксы и т.д.), в GUI существуют еще виджеты-композиты (SpinButton, CheckBox, ComboBox и т.д.). Для доступа к элементам композита используют селектор объекта-композита, после него два двоеточия и специальный идентификатор элемента. Например стилевое правило:
Код

QComboBox::drop-down { image: url(dropdown.png) }

задает картинку из файла dropdown.png для кнопки справа, открывающей выпадающий список, в объекте QComboBox.

Специальные идентификаторы для элементов композита. В Qt сейчас поддерживаются следующие имена:
::down-arrow - стрелка вниз для QComboBox или QSpinBox.
::down-button - нижняя кнопка для QSpinBox.
::drop-down - раскрывающая выпадающий список кнопка QComboBox.
::indicator - индикатор для QCheckBox, QRadioButton или для checkable QGroupBox.
::item - элемент QMenuBar, QMenu или QStatusBar.
::menu-indicator - индикатор меню для QPushButton.
::title - заголовок QGroupBox.
::up-arrow стрелка вверх для QSpinBox.
::up-button - верхняя кнопка QSpinBox.

Для отображения GUI в динамике в селектор можно включать псевдо-состояние. Псевдо-состояние записывается в селекторе последним элементом и отделяется от предыдущей части двоеточием. Пример:
Код

QPushButton { background-color : white }
QPushButton:hover { background-color : red }
QPushButton:pressed { background-color : green }

определяет для всех кнопок стиль с белыми кнопками, которые при наведении на них мыши становятся красными, а при нажатии - зелеными.

Поддерживаемые в Qt на данный момент псевдо-состояния:
:checked 
:disabled 
:enabled
: focus
:hover 
:indeterminate 
:off 
:on 
:pressed 
:unchecked 

Продолжение следует.

Это сообщение отредактировал(а) Artemios - 24.6.2007, 23:24

Присоединённый файл ( Кол-во скачиваний: 95 )
Присоединённый файл  qss_example.tar.bz2 5,46 Kb


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Artemios
Дата 24.6.2007, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



...

Это сообщение отредактировал(а) Artemios - 16.1.2009, 02:18


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Goganchic
Дата 25.6.2007, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 678
Регистрация: 18.6.2004

Репутация: 2
Всего: 5



А может это дело оформить как статью?

Artemios, как думаешь?
PM Jabber   Вверх
Artemios
Дата 25.6.2007, 23:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Goganchic, позже будет и статья. Я пока еще в процессе "рождения" материала, по ходу дела выкладываю сюда, редактирую...
Жду обратной реакции для коррекции своих трудов. Без отклика заинтересованного читателя трудно решить, что и как лучше писать, где лучше подробные объяснения, а где - лишь упоминание и отсылка к документации... Вот, например, на стили кажется слишком много развернулся, сокращать надо будет...
В общем, мне бы хотелось комментариев, критики, и чем больше - тем лучше для будущего материала... smile


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
cab
Дата 26.6.2007, 14:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 26.6.2007

Репутация: нет
Всего: нет



Цитата(Artemios @  25.6.2007,  23:37 Найти цитируемый пост)
В общем, мне бы хотелось комментариев, критики, и чем больше - тем лучше для будущего материала...
Отличный старт. Продолжайте в том же духе. Жду с нетерпением

PM MAIL   Вверх
Polimer
Дата 10.7.2007, 16:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 10.7.2007

Репутация: нет
Всего: нет



ЗдОрово написано!
Так популярно и на русском только здесь нашел. Очень хочется увидеть продолжение темы.
Уже качаю Qt.

Автору мегаплюс. Пишите еще, я думаю, многие заинтересованы.
PM MAIL   Вверх
pythonwin
Дата 11.7.2007, 07:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 2529
Регистрация: 18.4.2006
Где: за компом

Репутация: 2
Всего: 36



[оффтоп]
для тех кто использует pyQT - Artemios, как я понимаю пишет статьи на форуме чтобы их критиковали. хотя "спасибо"  думаю тоже приятно smile
[/оффтоп]
PM WWW GTalk Jabber   Вверх
maitreya
Дата 24.7.2007, 15:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 24.7.2007

Репутация: 1
Всего: 1



Очень хорошая документация.
На мой взгляд нужно рассмотреть работу с utf
PM ICQ Jabber   Вверх
keiman
  Дата 4.8.2007, 19:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 4.8.2007

Репутация: 1
Всего: 1



Во-первых, огромное спасибо за проделанный труд! smile 

Во-вторых, как и другие посетители форума с интересом продолжал бы следить за развитием цикла постингов на эту тему.

По поводу стиля написания и тд: стиль доступный и в тоже время не совсем расчитанный на идиотов, отлично что приведены результаты работы скриптов в виде скриншотов, единственное критическое замечание: было бы неплохо задавать все комментарии в примерах (листингах), а те которые "не помещаются", а также ссылки на подробные описания свойств и методов просто ссылками на документацию - все-таки это "путеводитель" по миру Qt, а не справочник описывающий возможности библиотеки ;)

По будущему содержанию: думаю вопросам типа "Работа с дизайнером графического интерфейса" можно уделять меньше внимания, а больше "ручным" аспектам, именно аспектам внутреннего устройства PyQt и его точек соединения с Pure Python. Другими словами лучше подробнее описать связывание своего Python-кода (кода программы) c GUI, все тонкости и хитрости связанные с разработкой GUI-приложений на Python (сигналы/слоты, утечки памяти), может быть заострить внимание на разнице в логике построения между GUI-приложениями и обычными Python-скриптами.  

Также неплохо чтобы были вкратце освещены вопросы "переносимости" Python+PyQt кода в другие реализации Пайтона (возможность переноса например в IronPython или JPython, а точнее видимо невозможность), создание байт-кода и тд.

И еще благодарность за написанный труд! Ждем продолжений!

Добавлено через 5 минут и 6 секунд
Друзья, а почему так не много откликов?

Неужели лень написать благодарность и дать небольшие комментарии или когда дело касается не личного (шкурного) интереса типа "посмотрите, мой код не исполняется. где ошибка?" вам уже ничего не интересно???
PM MAIL   Вверх
keiman
Дата 4.8.2007, 20:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 4.8.2007

Репутация: 1
Всего: 1



Цитата(Artemios @ 24.6.2007,  23:21)
В планах на будущее:
Завершить рассмотрение Qt Style Sheets.

Работа с дизайнером графического интерфейса;
система ресурсов приложения;
реализованная в Qt технология MVC на примере работы с базами данных и XML;
и много иного, оставайтесь с нами.
Artemios.

Да, вдогонку.

Уделите, пожалуйста, внимание оптимальному способу "прикручивания" *.ui к Python-коду (генерирование в pyQt, pyuic и тд)
PM MAIL   Вверх
setq
Дата 5.8.2007, 07:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 707
Регистрация: 28.9.2003

Репутация: нет
Всего: 26



Цитата(keiman @  4.8.2007,  19:34 Найти цитируемый пост)
Неужели лень написать благодарность и дать небольшие комментарии


Мы просто ленивые. Отличные статьи, Artemios)
PM MAIL   Вверх
FunnyFalcon
Дата 5.8.2007, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 76
Регистрация: 27.3.2006

Репутация: нет
Всего: 7



Цитата

Мы просто ленивые. Отличные статьи, Artemios) 

+1 . Если б мог, то и на плюсик нажал бы.
Очень жду продолжение цикла.
PM MAIL   Вверх
keiman
  Дата 6.8.2007, 12:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 4.8.2007

Репутация: 1
Всего: 1



Кстати,

больше 50% оставивших здесь отзывы - новички, которые до сих пор (до этого постинга) не имели ни одного сообщения на форуме, другими словами зарегистрировались ради того, чтобы поблагодарить автора и ждать продолжения.

Это дорогого стОит (IMHO).
PM MAIL   Вверх
Artemios
Дата 17.8.2007, 02:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Огромное всем спасибо за такие теплые отзывы и комментарии.
Да, pythonwin прав, мне нужна именно критика для полировки и пополнения текста, потому отдельное спасибо keiman, постараюсь учесть.
Прошу прощения, что так долго не продолжаю (сами понимаете: лето, семья, дети -- совместный отдых...), но с сентября торжественно обещаю продолжить работу smile . 

Цитата(keiman @  4.8.2007,  20:34 Найти цитируемый пост)
Также неплохо чтобы были вкратце освещены вопросы "переносимости" Python+PyQt кода в другие реализации Пайтона (возможность переноса например в IronPython или JPython, а точнее видимо невозможность)

Переносимость Python+PyQt кода пока невозможна. Поясню: есть язык Python, а есть платформа CPython, как альтернатива платформам .NET и Java. PyQt -- это пристройка к CPython, привязывающая к платформе "нативную" библиотеку Qt. 
IronPython и JPython -- языковые расширения соответствующих (иных) платформ. То есть мы здесь получаем удобный, привычный синтаксис для написания кода под соответствующую платформу. Имеем доступ ко всем или большинству библиотек платформы, а также возможность использовать Pure Python библиотеки.

Допустим, мы хотим использовать некоторую не-pure-python библиотеку, имеющуюся в CPython (назовем ее anylib), на иной платформе. Естественно, саму anylib мы использовать не сможем, но хотим переносимости программы, использующей anylib. Другими словами, нам требуется наличие точно такого же интерфейса и поведения. 
Пути разрешения: либо поиск на целевой платформе уже имеющегося функционала, организующего аналогичное поведение и далее оборачивание этого функционала Python-кодом, реализующим интерфейс anylib (по этому пути, например, идут в проекте FePy -- интерфейс большинства стандартных модулей CPython, а внутри -- вызовы .NET-библиотечных функций), либо первоначально расширение функционала целевой платформы.

По поводу расширения функционала -- это в принципе возможно и частично делается (для .NET (а точнее для Mono) видел под линукс привязку Qt старой уже 3-й версии -- думаю будут и более новые; для Java -- сами Trolltech-и разрабатывают Qt Jambi). Другое дело, что использование этого функционала из IronPython или Jython будет уже обусловлено особенностями привязки Qt к конкретной платформе, то есть интерфейс и идеология могут сильно отличаться от PyQt (ведь привязка PyQt изначально разрабатывалась с ориентировкой на особенности языка Python (динамическая типизация, объекты первого класса...), чего нельзя будет сказать ни о Qt#, ни о Qt Jambi)



--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Nashev
Дата 6.1.2008, 22:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 6.1.2008

Репутация: нет
Всего: нет



Цитата(Artemios @  15.6.2007,  20:22 Найти цитируемый пост)
      
Код

       # создаем соединения:
        self.connect(spinbox, QtCore.SIGNAL("valueChanged(int)"), \
                slider, QtCore.SLOT("setValue(int)"))
        self.connect(slider, QtCore.SIGNAL("valueChanged(int)"), \
                spinbox, QtCore.SLOT("setValue(int)"))
        self.connect(spinbox, QtCore.SIGNAL("valueChanged(int)"), self.log_to_console)


каким образом тут избегается зацикливание отправки сигналов? По какой причине, например, спинбокс, при обработке сигнала от слайдера, не посылает сигнал обратно слайдеру о том, что у него значение поменялось? Или посылает? А тогда почему слайдер, реагируя на этот сигнал, не шлёт сигнал опять? Ведь точно не шлёт?

А вот на спинбоксе висит ещё получатель окно - оно сигнал не получит, если сигнал от слайдера придёт? или получит? А если сигнал от самого спинбокса идёт, окно не получит ещё и эхо ответного сигнала от слайдера? как это вообще разруливается?

В общем, про это стоит вкратце написать прямо там, у примера.


PM MAIL   Вверх
vva
Дата 27.6.2008, 08:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 27.6.2008

Репутация: нет
Всего: нет



Здраствуйте!
У меня не получается корректно установить QtPy.
После установки python-2.5.2.msi и PyQt-Py2.5-gpl-4.4.2-1.exe
Запускаю скрипт 
import sys
from PyQt4.QtGui import QApplication
from myplayer import MyPlayer # подключаем диалог плеера
        
if __name__=="__main__":
    app = QApplication(sys.argv)    
    player = MyPlayer() # создаем диалог класса
    player.show() # показыв
аем диалог
    app.exec_()

выдает ошибку Точка входа в процедуру _ZN10QBoxLayout13addSpacerItemEP11SpacerItem не найдина в библиотеки DLL QtGui4.dll

ЧТО ДЕЛАТЬ?
PM MAIL   Вверх
KiberJo
Дата 30.7.2008, 09:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 30.7.2008

Репутация: нет
Всего: нет



Замечательная ветка Хотелось бы продолжения...
PM MAIL   Вверх
OVirk
Дата 9.9.2008, 07:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 21.5.2008

Репутация: нет
Всего: нет



спасибо Artemios, за вашу  статью!

Объясните, пожалуйста, подробнее о том как получить из формы сделанной в Designer, файл .ui, форму в виде файла .py?

Добавлено через 6 минут и 30 секунд
спасибо Artemios, за вашу  статью!

Объясните, пожалуйста, подробнее о том как получить из формы сделанной в Designer, файл .ui, форму в виде файла .py? 
PM MAIL   Вверх
se214
Дата 29.9.2008, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 29.9.2008
Где: Ижевск

Репутация: нет
Всего: нет



Artemios, огромное спасибо за статью. 
Когда-то очень мне помогла быстро разобраться с PyQt.
Хотелось бы увидеть продолжения: QtDisigner, uic, pyqtSignature. В ближайшее время возможно буду с этими вопросами, если разберусь - постараюсь написать статью.
PM MAIL ICQ   Вверх
nerezus
Дата 29.9.2008, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



Цитата

Объясните, пожалуйста, подробнее о том как получить из формы сделанной в Designer, файл .ui, форму в виде файла .py?
 

\Python25\Lib\site-packages\PyQt4\uic\pyuic.py FormLab1.ui > ui_FormLab1.py


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
OldDed
Дата 15.10.2008, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 15.10.2008

Репутация: нет
Всего: нет



Цитата(Artemios @ 25.6.2007,  23:37)
GoganchicВот, например, на стили кажется слишком много развернулся, сокращать надо будет...
В общем, мне бы хотелось комментариев, критики, и чем больше - тем лучше для будущего материала... smile

Отличная статья!Спасибо!
А вот сокращать ничего ненадо.Подробнее - интереснее
Ждем продолжения.


Это сообщение отредактировал(а) OldDed - 15.10.2008, 17:53
PM MAIL   Вверх
OldDed
Дата 16.10.2008, 18:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 15.10.2008

Репутация: нет
Всего: нет



Hi All!
Для того чтобы такая программа работала у пользователя нужно устанавливать :
Python+Sip+Qt4+PyQt или как?
Спасибо!

PM MAIL   Вверх
nerezus
Дата 16.10.2008, 20:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



OldDed, Python + PyQt


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
OldDed
Дата 17.10.2008, 11:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 15.10.2008

Репутация: нет
Всего: нет



Цитата(nerezus @ 16.10.2008,  20:17)
OldDed, Python + PyQt

Hi All!
Понял.Спасибо!
А вот может где есть почитать про инсталяцию готовой программы у пользователя.
Может есть что-то,типа InstallShield
Спасибо.
PS: Я тут приложил картинку с ошибкой.Как такое лечится?



Это сообщение отредактировал(а) OldDed - 17.10.2008, 11:49

Присоединённый файл ( Кол-во скачиваний: 33 )
Присоединённый файл  Error.JPG 9,04 Kb
PM MAIL   Вверх
AriX
Дата 28.10.2008, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 311
Регистрация: 16.6.2003

Репутация: нет
Всего: 19



OldDed, надо запускать не uic, а pyuic4.py
PM MAIL   Вверх
dimitor
Дата 24.11.2008, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 24.11.2008

Репутация: нет
Всего: нет



Жаль что тема умерла...
Первый приличный источник на русском по основам PyQt4.
Может топикстартер выложит хотя-бы список толковой документации/линков на документацию/саму документацию?
ЗЫ и так с гугла пришел
PM MAIL   Вверх
Enchantner
Дата 11.12.2008, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 21.9.2007

Репутация: нет
Всего: нет



Товарищи, это, конечно, кощунство, но где достать плагин для eclipse для рисования QT-интерфейсов под Python? Потому что под С++ такой Qt Designer давно есть, а вот под питон...Привык, понимаешь, компоненты вручную распихивать...
PM MAIL   Вверх
alex_smirnov
Дата 11.12.2008, 15:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 194
Регистрация: 22.6.2007
Где: Санкт-Петербург

Репутация: нет
Всего: 4



Тот же самый Qt designer.

Как это делается
PM GTalk Jabber   Вверх
Sergey912
Дата 11.1.2009, 06:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 3.1.2007

Репутация: нет
Всего: нет



Спасибо автору! Только сейчас заметил такой хороший мануал smile
Вот только одна проблема MinGW при установке выдает ошибку:


Цитата

File already exists - skipping mingw-runtime-3.14.tar.gz
File already exists - skipping w32api-3.11.tar.gz
Downloading binutils-2.16.91-20060119-1.tar.gz
Downloading gcc-core-3.4.2-20040916-1.tar.gz
Create folder: C:\MinGW
Extract: C:\MinGW\installed.ini... 100%
Extracting mingw-runtime-3.14.tar.gz
untgz::extract -d 'C:\MinGW' -z 'C:\Documents and Settings\Admin\Ðàáî÷èé ñòîë\mingw-runtime-3.14.tar.gz' 
gzread: incomplete block read
Error: Failure reading from tarball.


Уже разобрался, архивы почему-то все битые скачались

Это сообщение отредактировал(а) Sergey912 - 11.1.2009, 06:50
PM MAIL WWW   Вверх
Artemios
Дата 16.1.2009, 01:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Sergey912
я это дело, первые посты, давно писал - сейчас в Windows таких сложностей не требуется.
Т.е. если планируешь писать только на Python-е, то MinGW и Qt (С++) не нужны.
Достаточно иметь Python и скачать PyQt.


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Artemios
Дата 17.1.2009, 04:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50





--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
Sergey912
Дата 17.1.2009, 14:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 174
Регистрация: 3.1.2007

Репутация: нет
Всего: нет



Artemios
А как потом это пользователю показать? Меня только одно сдерживает - просить помимо программы скачать еще 2 "хвоста" и установить, которые вобщем весят немало  smile 
PM MAIL WWW   Вверх
nerezus
Дата 17.1.2009, 15:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



Sergey912, сделай инсталлер.


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
Artemios
Дата 17.1.2009, 17:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 405
Регистрация: 14.8.2006
Где: Саратов, Россия

Репутация: 9
Всего: 50



Sergey912
простейший вариант - использовать py2exe


--------------------
fib = 1: 1: [ x+y | (x,y) <- zip fib (tail fib) ]
PM MAIL   Вверх
unel
  Дата 22.5.2009, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 12
Регистрация: 21.10.2005

Репутация: нет
Всего: нет



круто! продолжение будет? очень заинтересовало)
PM MAIL ICQ   Вверх
Arahnus
Дата 28.10.2009, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 12.5.2009

Репутация: нет
Всего: нет



Цитата
простейший вариант - использовать py2exe


А разве файл не получиться большой и громозкий? Я читал что эта прога пакует интерпретатор и программу в один exe- кусок.
Может быть лучше что то вроде psyco? Тоесть надо искать способ создания и программы на питоне исходного кода на С++ и последующей компиляции в exe. Только я этим не пользоваля. Сам хочу еще разобраться.

А как без PyQt работает IDLE? Ведь должны же быть какие то родные средства для создания окон. Например в java есть swing и awt.

Меня лично тоже интересует вопрос переносимости на разные компьютеры.



Это сообщение отредактировал(а) Arahnus - 28.10.2009, 17:13
PM MAIL   Вверх
nerezus
Дата 28.10.2009, 17:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



Цитата

А разве файл не получиться большой и громозкий? Я читал что эта прога пакует интерпретатор и программу в один exe- кусок.
 Если для вас 10мб - это много, то получится. Для большинства это не много.

Цитата

А как без PyQt работает IDLE? Ведь должны же быть какие то родные средства для создания окон. Например в java есть swing и awt.
 Tk в составе питона.

Цитата

Может быть лучше что то вроде psyco? 
 Посмотрите в википедии, что значит термин JIT.

Цитата

Меня лично тоже интересует вопрос переносимости на разные компьютеры.
 Переносим в пределах одной ОС.

Цитата

Тоесть надо искать способ создания и программы на питоне исходного кода на С++ и последующей компиляции в exe. 
 Слов набор считаю бессмысленный это.


--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
Arahnus
Дата 28.10.2009, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 29
Регистрация: 12.5.2009

Репутация: нет
Всего: нет



[quote] Переносим в пределах одной ОС.[quote]

В смысле GUI что ли? А если на разных ОС есть PyQt?


[quote]  Посмотрите в википедии, что значит термин JIT.[quote] 
Я знаю что это.
Хотите сказать что psyco переводит байт-код из питоновского в понятный для Windows?

Цитата
Слов набор считаю бессмысленный это.


Я хотел сказать про это:
Цитата

Shed Skin - experimental Python-to-C++ compiler
Транслятор Python скриптов в оптимизированное C++ представление. От существующих компиляторов Python кода, Shed Skin отличается значительно более высокой производительностью. Например, на 16 нетривиальных тестовых программах код сгенерированный Shed Skin оказался в 2-40 раз быстрее Psyco и в среднем в 12 раз быстрее CPython. 

Ограничением Shed Skin является возможность компиляции скриптов в которых используются только статические типы данных, а также существенные ограничения на использование функций стандартной библиотеки.Подробный рассказ о методах работы продукта представлены в данном PDF документе. http://kascade.org/shedskin.pdf


В общем интересует возможность на python'e писать программы которые можно бы было откомпилировать в gcc так чтобы программа получилась независима от питона.
PM MAIL   Вверх
nerezus
Дата 28.10.2009, 19:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вселенский отказник
****


Профиль
Группа: Участник
Сообщений: 3330
Регистрация: 15.6.2005

Репутация: нет
Всего: 43



Цитата

В смысле GUI что ли? А если на разных ОС есть PyQt?
 Ну если эти известные вам ОС умеют запускать win32 exe файлы - то да, будет работать на всех )

Цитата

Хотите сказать что psyco переводит байт-код из питоновского в понятный для Windows?
 psyco добавляет JIT-компиляцию в питон.

Цитата

Ограничением Shed Skin является возможность компиляции скриптов в которых используются только статические типы данных, а также существенные ограничения на использование функций стандартной библиотеки.
 Вобщем он не может компилировать программу больше нескольких строк, судя по этому выражению ;)

Цитата

В общем интересует возможность на python'e писать программы которые можно бы было откомпилировать в gcc так чтобы программа получилась независима от питона.
 Это невозможно, т.к. язык имеет многое из того, что нельзя скомпилировать. Шедскин решило просто создать свой язык с питоноподобным синтаксисом и кастрированными возможностями ;)

+ кто-то забывает, что сами либы Qt  весят гораздо больше, чем питон, поэтому разница в размере бинарника на C++ и на питоне будет незначительна.




--------------------
Сообщество художников Artsociety.ru
PM MAIL WWW   Вверх
stasnam
Дата 13.1.2010, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 13.1.2010

Репутация: нет
Всего: нет



Спасибо.
PM MAIL   Вверх
Пеппи
Дата 17.2.2010, 19:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 4.7.2009

Репутация: нет
Всего: нет



Спасибо  smile 
PM MAIL   Вверх
VitAl2013
  Дата 19.11.2010, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 19.11.2010

Репутация: нет
Всего: нет



Я может офигеть и опоздал, но расскажу как устанавливал на Убунту (10.10 в частности) с 0.  smile 
Для начала надо установить всё что связанно с Pythin2.6. В конце надо установить пакеты python2.6-dev и python2.6-dev-all (один пакет тянет другой. так что не промахнётесь).
Потом распаковываем SIP куда-нить в загрузки (я Извинды вышел, тапком не бить, если я что-то не так сделал)
терминалом добираемся до этой папки и произносим в него описанные в первом посте заклинания.
Если вылезло что-то типа "...gcc..." и "...g++..." то ищем этот компилятор - он сам при установке отсутствует.
Если вылезно типа "...Python.h..." - это значит либо нет тех 2х пакетов либо они стали криво либо перепутана версия и вы поставили их для 3.1
PyQt мэйкается раз в 20 дольше SIP.

Удалось запустить примеры из первого поста. Но...

Мне не удалось победить отказы запускаться у скриптов содержащих кириллицу что в коментах (пришлось их того). Это связанно с тем что файлы должны быть запечатаны в древний АСКИИ (гори он синим пламенем  smile ), а Убунту давно на юникоде. Это проблема.  smile 

Победил!  smile  Секрет в строчке # -*- coding: utf-8 -*- и редакторе SciTe... CodeLight не умеет запускать скрипты.

Вообще какие редакторы посоветуете для работы с python и PyQt в частности?

Это сообщение отредактировал(а) VitAl2013 - 19.11.2010, 12:08
PM MAIL   Вверх
Ginibe
Дата 14.6.2011, 09:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 2.5.2011
Где: Киев

Репутация: нет
Всего: нет



Отличный материал для начала изучения.
Респект автору. Сам недавно начал изучение, статья очень помогла.

Вот такая просьба: если у автора есть опыт по использованию виджета QTableWidget то поделитесь в подобной форме, уж очень "никак" сделана родная документация, чесн слово ...
С уважением !


Это сообщение отредактировал(а) Ginibe - 14.6.2011, 09:55
PM MAIL   Вверх
mrDoctorWho
Дата 29.10.2011, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 6
Регистрация: 28.10.2011

Репутация: нет
Всего: нет



Понимаю, что прошло очень много времени, но...
Спасибо за такие подробные описания. Всё чётко и ясно, только вот я не нашёл того, что искал. 

PM MAIL   Вверх
Seganapa
Дата 10.10.2012, 09:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 10.8.2012

Репутация: нет
Всего: нет



Да, информация очень полезна! Но есть несколько вопросов по теме, на которые не могу найти ответы ни в литературе ни в других форумах. Очень жаль что эта тема не активна!!!
PM MAIL   Вверх
Aleksey1987
Дата 10.3.2013, 20:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 9.3.2013

Репутация: нет
Всего: нет



Ребята, вопрос по PyQt. В архиве пример скрипта. При на жатии на кнопку "Генерировать" тестовая функция не обновляет данные объекта, а отдает те, которые стоят по умолчанию. Я в ступоре.

Присоединённый файл ( Кол-во скачиваний: 8 )
Присоединённый файл  GenMD5.rar 8,44 Kb
PM MAIL   Вверх
rsm
Дата 17.3.2013, 07:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник Клуба
Сообщений: 999
Регистрация: 16.3.2005

Репутация: нет
Всего: 62



Цитата(Aleksey1987 @  10.3.2013,  22:37 Найти цитируемый пост)
тестовая функция не обновляет данные объекта, а отдает те, которые стоят по умолчанию. Я в ступоре

Судя по примеру, данные объекта заполняются только конструкторе. Конструктор по определению вызывается только один раз. Стало быть и значения всегда будут одинаковыми.
PM MAIL   Вверх
leden1981
Дата 18.10.2013, 18:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 1
Регистрация: 22.11.2009

Репутация: нет
Всего: нет



Отличная статься! Единственная понятная документация по PyQT. Спасибо автору!
PM MAIL   Вверх
Google
  Дата 8.12.2019, 11:44 (ссылка)  





  Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Python: Разработка GUI | Следующая тема »


 




[ Время генерации скрипта: 0.2891 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.