Как передать строку в qdatetimeedit
Перейти к содержимому

Как передать строку в qdatetimeedit

  • автор:

Как изменить время в QDateTimeEdit

Имеется переменная date , которая имеет тип QDateTimeEdit . date.dateTime() имеет тип QDateTime . Как добавить или вычесть несколько дней или часов?

Отслеживать
73.5k 110 110 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков
задан 31 авг 2021 в 14:42
1,159 1 1 золотой знак 10 10 серебряных знаков 20 20 бронзовых знаков

1 ответ 1

Сортировка: Сброс на вариант по умолчанию

import sys from PyQt5.Qt import * class MyWin(QWidget): def __init__(self): super().__init__() lblCurrentDateTime = QLabel() self.lblDateTimeEdit = QLabel() btn_days = QPushButton("DateTime + 7 days") btn_days.clicked.connect(self.editDateDay_days) btn_hours = QPushButton("DateTime + 2 hours") btn_hours.clicked.connect(self.editDateDay_hours) lblCurrentDateTime.setText( QDateTime.currentDateTime().toString('yyyy MM dd hh:mm:ss')) self.dateTimeBegin = QDateTimeEdit() self.dt = self.dateTimeBegin.dateTime().currentDateTime() lay = QVBoxLayout(self) lay.addWidget(lblCurrentDateTime) lay.addWidget(self.lblDateTimeEdit) lay.addWidget(btn_days) lay.addWidget(btn_hours) def editDateDay_days(self): self.dateTimeBegin.setDateTime(self.dt.addDays(7)) self.dt = self.dt.addDays(7) currentTime = self.dateTimeBegin.dateTime().toString( 'yyyy MM dd hh:mm:ss') self.lblDateTimeEdit.setText( self.dateTimeBegin.dateTime().toString('yyyy MM dd hh:mm:ss')) def editDateDay_hours(self): self.dateTimeBegin.setDateTime(self.dt.addSecs(1*60*60*2)) self.dt = self.dt.addSecs(1*60*60*2) currentTime = self.dateTimeBegin.dateTime().toString( 'yyyy MM dd hh:mm:ss') self.lblDateTimeEdit.setText( self.dateTimeBegin.dateTime().toString('yyyy MM dd hh:mm:ss')) if __name__ =="__main__": app = QApplication(sys.argv) w = MyWin() w.show() sys.exit(app.exec_()) 

введите сюда описание изображения

Отслеживать
ответ дан 31 авг 2021 в 15:22
73.5k 110 110 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков
Спасибо большое! Помогло
1 сен 2021 в 6:49

@helldrg Если мой ответ помог вам, то не забудьте пометить как правильный, если вы не знаете, как это сделать, проверьте ru.stackoverflow.com/tour

1 сен 2021 в 7:07
в моем случае не помогло, расписал в UDP
1 сен 2021 в 7:10

@helldrg в вашем примере есть скрытая ошибка. Замените строку class MainWindow(QtWidgets.QMainWindow, Ui_Form): на строку class MainWindow(QtWidgets.QWidget, Ui_Form): , а также замените addDays на addSecs

Programming / C++Programming / Qt / Qt-doc.ru / Дата и время в Qt

Работа с датой и временем в Qt осуществляется с помощью классов QDate , QTime и QDateTime , которые предназначены для хранения дат и времени и проведения с ними различных операций. Чаще всего требуется получение текущей даты и времени. Эти классы предоставляют методы для преобразования даты и времени в строку определенного формата. Также есть методы для проведения обратного преобразования — из строки. Таймер уведомляет приложение об истечении заданного промежутка времени. События таймера относятся к разряду внешних прерываний. Внешние прерывания — это прерывания, вызываемые асинхронными событиями, например, устройствами ввода/вывода или самим устройством таймера. Интервалы запуска таймера устанавливаются в миллисекундах. Недостаток состоит в том, что если программа занята интенсивными вычислениями, то события таймера могут быть обработаны по окончании процесса вычисления. При выходе из приложения таймеры автоматически уничтожаются. Приложениям часто требуется информация о дате и времени. Например, для выдачи отчетной информации или для реализации часов. Qt предоставляет для работы с датой и временем три класса: QDate , QTime и QDateTime , определенные в заголовочных файлах QDate , QTime и QDateTime . Класс QDate представляет собой структуру данных для хранения дат и проведения с ними разного рода операций. В конструкторе класса QDate передаются три целочисленных параметра. В первом передается год, во втором — месяц, а в третьем — день. Например, создадим объект, который будет содержать дату 25 октября 2004: QDate date(2007, 10, 25); Эти значения можно установить и после создания объекта с помощью метода setDate() . Например: QDate date; date.setDate(2007, 10, 25); Для получения значений года, месяца и дня, установленных в объекте даты, следует воспользоваться следующими методами: year() — возвращает целый год в диапазоне от 1752 до 8000; month() — возвращает целое значение месяца в диапазоне от 1 до 12 (с января по декабрь); day() — возвращает день месяца в диапазоне от 1 до 31. С помощью метода daysInMonth() можно узнать количество дней в месяце, а с помощью метода daysInYear () — количество дней в году. Для получения дня недели следует вызвать метод dayOfWeek() . Для получения дня года служит метод dayOfYear() . Можно также узнать номер недели, для чего нужно вызвать метод weekNumber() . Метод toString() позволяет получить текстовое представление даты. Можно определить собственный формат времени, передав в метод toString() строку-шаблон, описывающую его. Например:

QDate date(2007, 10, 25); QString str; str = date.toString( «d.M.yy» ); //str — «3.7.07» str = date.toString( «dd/MM/yy» ); //str — «03/07/04» str = date.toString( «yyyy.MMM.ddd» ) ; //str = «2007.июл.Сб» str = date.toString( «yyyy.MMMM.dddd» );//str = «2007.Июль.суббота» При помощи метода addDays() можно получить измененную дату, добавив или отняв от нее дни. Действия методов addMonths() и addYears() аналогичны, но разница в том, что они оперируют месяцами и годами. Например: QDate date(2007, 1, 3); QDate date2 = date.addDays(-7); QString str = date2.toString( «dd/MM/yy» ); //str = «27/12/06» Класс QDate предоставляет метод fromString() , позволяющий проводить обратное преобразование из строкового типа к типу QDate . Для этого, в первом параметре метода нужно передать формат. Одна из самых частых операций — получение текущей даты. Для этого нужно вызвать метод currentDate() . При помощи метода daysTo() можно узнать разницу в днях между двумя датами. Следующий пример определяет количество дней от текущей даты до Нового года: QDate dateToday = QDate::currentDate(); QDate dateNewYear(dateToday.year(), 12, 31); qDebug() << "Осталось " << dateToday.daysTo(dateNewYear) << " дней до Нового года" ; Объекты дат можно сравнивать друг с другом, для чего в классе QDate определены операторы ==, !=, и >=. Например: QDate datel(2007, 1, 3); QDate date2(2007, 1, 5); bool b = (datel == date2); //b = false Контроль над временем — очень важная задача, с помощью которой можно вычислять задержки в работе программы, отображать на экране текущее время, проверять время создания файлов и т. д. Для работы со временем библиотека Qt предоставляет класс QTime . Как и в случае с объектами даты, с объектами времени можно проводить операции сравнения ==, !=, или >=. Объекты времени способны хранить время с точностью до миллисекунд. В конструктор класса QTime передаются четыре параметра. Первый параметр задает часы, второй — минуты, третий — секунды, а четвертый —

миллисекунды. Третий и четвертый параметры можно опустить, по умолчанию они равны нулю. Например: QTime time(20, 4); Эти значения можно устанавливать и после создания объекта времени с помощью метода setHMS() . Например: QTime time; time.setHMS (20, 4, 23, 3); Для получения значений часов, минут, секунд и миллисекунд, установленных в объекте времени, в классе QTime определены следующие методы: hour() — возвращает положительные значения часа в диапазоне от 0 до 23; minute() — возвращает целое значение, обозначающее минуты, в диапазоне от 0 до 59; second() — возвращает целое значение, обозначающее секунды, в диапазоне от 0 до 59; msec() — возвращает целое значение в диапазоне от 0 до 999, представляющее собой миллисекунды. Класс QTime предоставляет метод toString() для передачи данных объекта времени в виде строки. В этот метод, в качестве параметра, можно передать одно из форматов времени или задать свой собственный. Например: QTime time(20, 4, 23, 3); QString str; str = time.toString( «hh:mm:ss.zzz» ); //str = «20:04:23.003» str = time.toString( «h:m:s ap» ); //str = «8:4:23 pm» При помощи статического метода fromString() можно произвести преобразование из строкового типа в тип QTime . Для этого, в первом параметре метода нужно передать одно из значений форматов. Получить измененный объект времени можно, добавив или отняв значения секунд (или миллисекунд) от существующего объекта. Эти значения передаются в методы addSecs() и addMSecs() . Для получения текущего времени в классе QTime содержится статический метод currentTime (). При помощи метода start() можно начать отсчет времени, а для того чтобы узнать сколько времени прошло с момента начала отсчета, следует вызвать метод elapsed(). Например, на базе этих методов можно сделать небольшой профайлер. Следующий пример вычисляет время работы функции test() : QTime time; time.start () ;

Данный подход обладает другим недостатком — он не асинхронен. То есть, наша программа будет в состоянии обрабатывать поступающие события, но не в состоянии исполняться дальше, пока цикл не завершится до конца. Таймер представляет собой решение этой проблемы. События таймера происходят асинхронно и не прерывают обработку других событий, выполняемых в том же потоке. Таймер — это гарант, обеспечивающий передачу управления программе. Долгая обработка событий влечет за собой задержки выполнения события таймера, то есть таймер ждет своего времени, как и остальные события. Период между событиями таймера носит название интервал запуска (firing interval). Таймер переходит в сигнальное состояние по истечении интервала запуска, который указывается в миллисекундах. Точность интервала запуска ограничивается, к сожалению, точностью системных часов, а это значит, что на таймер нельзя полагаться как на секундомер. ОС Windows 98 отличается самой плохой точностью — она составляет 55 миллисекунд, во всех же остальных ОС, поддерживаемых Qt, точность лежит в пределах одной миллисекунды. Следовательно, при написании программы имитации часов будет нелишним, после каждого сообщения таймера, проверять текущее время. Так как временной интервал, задаваемый в таймере, представляет собой целое число, то самый большой временной интервал, который можно установить — 24 дня. Эту проблему можно решить введением дополнительного счетчика для таймера. Существует много областей для применения таймера. Например, в текстовом редакторе его используют для автоматического сохранения файлов или в качестве альтернативы многопоточности, разбив программу на части, каждая из которых будет выполняться при наступлении события таймера. Также таймер используется для отображения информации о состоянии данных, изменяющихся с течением времени. Таймер незаменим для избежания разногласий, связанных с мощностью и возможностями разных компьютеров, то есть для исполнения программ в режиме реального времени. События таймера можно использовать и в мультипоточном программировании, для каждого потока, имеющего цикл сообщений (event loop). Для запуска цикла сообщений в потоке нужно вызвать метод QThread::exec() . Каждый класс, унаследованный от QObject , содержит свои собственные встроенные таймеры. Вызов метода QObject::startTimer() производит запуск таймера. В качестве параметра ему передается интервал запуска в миллисекундах. Метод startTimer() возвращает идентификатор, необходимый для распознавания таймеров, используемых в объекте. По истечении установленного интервала запуска генерируется событие QTimerEvent , которое передается В метод timerEvent() . Вызвав метод QTimerEvent::timerId() объекта события QTimerEvent , можно узнать идентификатор таймера, инициировавшего это событие. Идентификатор можно использовать для уничтожения таймера, передав его в метод QObject::killTimer() . В следующей программе отображается надпись, которая появляется и исчезает через заданные промежутки времени. <рисунок>int main ( int argc, char ** argv)

QApplication app (argc, argv);
BlinkLabel lbl( »

COLOR = RED>
Blink
» );

lbl.show(); return app.exec(); > В функции main() создается виджет класса BlinkLabel , в конструктор которого первым параметром передается отображаемый текст в формате RichText . class BlinkLabel : public QLabel < private : bool m_bBlink; QString m_strText; protected : virtual void timerEvent(QTimerEvent*) < m_bBlink = !m_bBlink; setText(m_bBlink ? m_strText : "" );

>
public :
BlinkLabel( const QString& strText,
int nInterval = 200,
QWidget* pwgt = 0
)

: QLabel(strText, pwgt) , m_bBlink( true ) , m_strText(strText) < startTimer(nInterval); >>; Класс BlinkLabel содержит атрибут булевого типа m_bBlink , управляющий отображением надписи, и атрибут m_strText , содержащий текст надписи. В конструктор класса BlinkLabel передается интервал мигания nInterval . По умолчанию он равен 200 миллисекундам. Вызов метода startTimer() запускает таймер со значением переданного интервала запуска. По истечении этого интервала происходит создание события QTimerEvent , которое передается в

метод timerEvent() , в котором происходит смена значения атрибута m_bBlink на противоположное. И в соответствии с установленным значением, методом setText() выполняется одно из действий: false — вся область надписи очищается установкой пустой строки; true — текст надписи устанавливается заново. Использование объекта класса QTimer гораздо проще, чем использование события таймера, определенного в классе QObject . К недостаткам работы с событием таймера относится необходимость наследования одного из классов наследующих QObject . Затем, в унаследованном классе нужно реализовать метод, принимающий объекты события таймера. А если в объекте создается более одного таймера, то возникает необходимость различать таймеры, чтобы узнать, который из них явился инициатором события. Для ликвидации этих неудобств Qt предоставляет класс таймера QTimer , являющийся непосредственным наследником класса QObject . Чтобы запустить таймер, нужно создать объект класса QTimer , а затем вызвать метод start() . В параметре метода передается значение интервала запуска в миллисекундах. Класс QTimer содержит статический метод singleshot() для одноразового режима отработки таймера ( singleshot ). С его помощью можно запустить одноразовый таймер без создания объекта класса QTimer . Первый параметр метода задает интервал запуска, а второй — является указателем на объект, с которым должно осуществляться соединение. Слот для соединения передается в третьем параметре. Этим можно воспользоваться, например, для прекращения работы демо-версии программы через 5 минут после ее запуска. int main( int argc, char ** argv) < QApplication app(argc, argv); MyProgram myProgram; QTimer::singleShot(5 * 60 * 1000, &app, SLOT (quit())); myProgram.show(); return app.exec(); >По истечении интервала запуска таймера высылается сигнал timeout() , который нужно соединить со слотом, выполняющим нужные действия. При помощи метода setInterval() можно изменить интервал запуска таймера. В том случае, если таймер был активен, он будет остановлен и запущен с новым интервалом, и ему будет присвоен новый идентификационный номер. При помощи метода isActive() можно проверить, находится таймер в активном состоянии. Вызовом метода stop() можно остановить таймер. Программа, окно которой изображено на рисунке, реализует часы, отображающие дату и время. Отображаемая информация актуализируется в соответствии с установленным полусекундным интервалом запуска таймера.

#include class Clock : public QLabel < Q_OBJECT public : Clock(QWidget* pwgt = 0) : QLabel(pwgt) < QTimer* ptimer = new QTimer( this ); connect(ptimer, SIGNAL (timeout()), SLOT (slotUpdateDateTime())); ptimer->start(500); slotUpdateDateTime(); > public slots: void slotUpdateDateTime() < QString str = QDateTime::currentDateTime().toString(Qt::SystemLocaleDate); setText( "

» + str + «

» ); > >; #endif //_Clock_h_ В конструкторе класса Clock создается объект таймера (указатель ptimer). Его сигнал timeout() соединяется со слотом, ответственным за обновление Отображаемой информации slotUpdateDateTime() . Вызов метода start() запускает таймер. В него передается интервал запуска. Слот slotUpdateDateTime() получает актуальную дату и время с помощью метода currentDateTime() . Затем он, с параметром локализации Qt::SystemLocaleDate преобразовывает дату и время к строковому типу и передает, для отображения, в метод setText() . В качестве альтернативы, в Qt предусмотрено минималистическое решение для таймера — это класс QBasicTimer , пред оставляющий только четыре метода: isActive(), start(), stop(), timerId(). Данные методы по своей функциональности, аналогичны методам класса QTimer . Исключение составляет только метод start() . Помимо первого параметра,

задающего интервал, в этот метод, вторым параметром, передается указатель на объект QObject , который будет получать события таймера. То есть, вам нужно будет реализовать в классе, унаследованном от QObject , метод обработки события таймера QObject::timerEvent() .

Как передать строку в qdatetimeedit

Полная версия этой страницы: Qt Модель/Представление

  1. Выравнивание колонок в QTableView (3 ответов)
  2. Поле Даты в ячейке QTableView (0 ответов)
  3. Ячейка TableView (1 )
  4. Делегат QComboBox в модели QTableView (2 ответов)
  5. TableView, авторазмер ячеек по содержимому (2 ответов)
  6. QTableView. Как убрать подсветку при выделении? (5 ответов)
  7. Как прикрутить несколько моделей к одному представлению? (3 ответов)
  8. Qt4.8 QComboBox внутри QTableView (1 )
  9. одна модель QAbstractTableModel и несколько таблиц QTableView (7 ответов)
  10. Вывести в combobox значения 2-х столбцов (1 )
  11. QDataWidgetMapper и несколько QCombobox (2 ответов)
  12. QSqlRelationalTableModel и fieldIndex в дочернем классе. (2 ответов)
  13. QAbstractItemModel и Drag and Drop (4 ответов)
  14. Установка фильтра, да не простого, а с несколькими or (2 ответов)
  15. QFileSystemModel и полное сканирование папок (9 ответов)
  16. QFileSystemModel и сигнал о перемещении файла (10 ответов)
  17. QComboBox, модель, пустое поле (2 ответов)
  18. QStyledItemDelegate не отображает данные модели в QTreeView (2 ответов)
  19. В модели показывается 1 столбец, а их должно быть несколько (2 ответов)
  20. Выборка из 3-х таблиц с возможностью редактирования. Нужна помощь (5 ответов)
  21. Не обновляется модель QsqlRelationTableModel (2 ответов)
  22. QVariant data() роли. (10 ответов)
  23. Вытащить индекс из модели для мапера (4 ответов)
  24. Растяжение столбов (1 )
  25. QSortFilterProxyModel + QAbstractItemModel + QTreeView (3 ответов)
  26. QSqlRelationalTableMode, сортировка выпадающего списка в QTableView (11 ответов)
  27. Как сделать такую модель/представление? (1 )
  28. как использовать QCompleter (0 ответов)
  29. Перенос строки из одного tableview в другой после двойного нажатия мышки (13 ответов)
  30. очистить контекстное меню QTableWidget (6 ответов)
  31. Qt5 не выделяет строку в QTableView при перемещении столбцов (0 ответов)
  32. CheckBox в QTableView (7 ответов)
  33. делагат для QTableWidget (7 ответов)
  34. QStandardModel и сигнал rowsInserted() (5 ответов)
  35. Делегат + QDateTimeEdit (2 ответов)
  36. Как отследить изменение, сделанное делегатом? (1 )
  37. Проблемы редактирования DOM модели (5 ответов)
  38. SQLite, TableModel и QueryModel (5 ответов)
  39. SIGSEGV при установлении модели ( QTableView->setModel ) (4 ответов)
  40. QSqlTableModel + proxy (0 ответов)
  41. Point3d (1 )
  42. QTreeView (0 ответов)
  43. Спозиционировать на запись в QSqlTableModel (2 ответов)
  44. QTableView + QAbstractTableModel data() (2 ответов)
  45. QTableView setModel() (4 ответов)
  46. Поиск и выбор узла в QTreeView (12 ответов)
  47. Добавление кнопки в QTableView через делегат. (3 ответов)
  48. QTreeView с фильтром на узлы для XML (2 ответов)
  49. Непонятное взаимодействие QTableView и обработчика нажатий клавиш (1 )
  50. Архитектура Модель-Представление (4 ответов)
  51. Не отображаются данные в таблице (1 )
  52. Как программно выделить строку в QListView? (1 )
  53. сортировка qfilesystemmodel (0 ответов)
  54. Cортировка и идексы (1 )
  55. Можно ли после создания модели поменять таблицу (3 ответов)
  56. Как в делегате реализовать открытие окна для редактирования (1 )
  57. QTableView + QSqlTableModel проблемы с добавлением строк (1 )
  58. QPushButton in editor (5 ответов)
  59. Переопределить rowcount() (1 )
  60. Как сделать, чтобы делегат отображался постоянно (4 ответов)
  61. QTableView (полупрозрачное выделение строки) (3 ответов)
  62. QTableView::edit( const QModelIndex index ) не работает (3 ответов)
  63. Много вопросов про модель\представление (9 ответов)
  64. QTableView автовысота строки (0 ответов)
  65. Когда уставливаю QCursor немедленно закрывается приложение (1 )
  66. как рисовать линию мышкой (1 )
  67. Отображение QAbstractItemModel на QSortFilterProxyModel (3 ответов)
  68. QSqlQuery (3 ответов)
  69. QTableView сортировка по нескольким колонкам одновременно и пример chap14 multisort из книги Земскова «Qt4 на примерах» (7 ответов)
  70. Позиционирование в QTableView & QSqlQueryModel (1 )
  71. Продолжаем разговор про QDataWidgetMapper (7 ответов)
  72. вопрос по QDataWidgetMapper (6 ответов)
  73. Вопросы по примеру staffmanager из книги Бланшет «Qt 4. Программирование GUI на C++» (22 ответов)
  74. Qt и реляционная модель (1 )
  75. Вопросы по примеру chap15 csvmodel из книги Земскова «Qt4 на примерах» (3 ответов)
  76. QTableView QScrollBar зависание. (2 ответов)
  77. как узнать координаты пикселе (6 ответов)
  78. Организация QListView (5 ответов)
  79. QGraphicsScene (1 )
  80. Несколько источников данных + одно представление (15 ответов)
  81. Не выводит вторые ветки TreeView (1 )
  82. Не могу найти пример для QListView::IconMode (0 ответов)
  83. Как в QTreeView отобразить одни столбцы, а в QTableView другие (1 )
  84. QTableView: Как задать цвет фона для одной секции заголовка? (7 ответов)
  85. Delegate в виде QTableView (2 ответов)
  86. Qwt выделение части графика (2 ответов)
  87. список моделей (2 ответов)
  88. Вывод даты и времени в таблице (3 ответов)
  89. Горячая клавиша поиска в QTableView (5 ответов)
  90. Несколько моделей, в QTreeView, связность. (6 ответов)
  91. Разные варианты выделения мышью в QTableView (4 ответов)
  92. QTreeWidget, QTreeWidgetItem Drag&Drop (0 ответов)
  93. QAbstractItemModel,QItemDelegate(вопрос новичка) (0 ответов)
  94. В чем хранить данные при создании собственной модели из QAbstractItemModel (5 ответов)
  95. Таблицы, модели, отображение (2 ответов)
  96. QSqlRelationalTableModel (4 ответов)
  97. Обновление модели при обновлении данных извне (1 )
  98. Добавление строки в модели (insertRow()) (3 ответов)
  99. как вернуть указатель? (12 ответов)
  100. QSqlRelationalTableModel обновление данных измененных сторонними программами (7 ответов)
  101. QItemSelectionModel — сигнал при снятии выделения с ячеек. (1 )
  102. QStandardItemModel — скорость создания элементов (10 ответов)
  103. Передать переменную из диалогового в главное окно (5 ответов)
  104. QTablView и блоки представления информции (2 ответов)
  105. QDataWidgetMapper и изменение foregn key (8 ответов)
  106. Qt: не добавляется виджет на сцену (1 )
  107. усовершенствовать QSqlRelationalTableModel (3 ответов)
  108. QTableView остаются артефакты делегатов (0 ответов)
  109. QDataWidgetMapper в диалоге. Как? (1 )
  110. сортировка чисел в QStandardItemModel (4 ответов)
  111. задача (4 ответов)
  112. Обновление нескольких QTableView одновременно (6 ответов)
  113. TreeModel + QSortFilterProxyModel + QTableView (5 ответов)
  114. Отображение иконки и текста в cell QTableView (2 ответов)
  115. QTreeView и база данных (7 ответов)
  116. Сохранение QtableWidget (4 ответов)
  117. SQL запрос в делегате. (3 ответов)
  118. выделение элементов после пересортировки (0 ответов)
  119. Правильное описание модели данных (2 ответов)
  120. соеденение древа и таблици (5 ответов)
  121. Одна модель и два представления (1 )
  122. Работа с QListView (1 )
  123. Редактирование и раскраска QTableView с клавиатуры (3 ответов)
  124. QListWidget и сортировка (0 ответов)
  125. QTableWidget (4 ответов)
  126. QGraphicsItem clipping (1 )
  127. Хитрый способ захвата данных из QTableView (7 ответов)
  128. изменение высоты ячеек QTableView, для которого установлен делегат на основе QTextEdit (16 ответов)
  129. QSqlTableModel и метод setQuery QSqlQueryModel *q=dynamic_cast(model) (23 ответов)
  130. QSortFilterProxyModel или как сделать фильтр с условием (a | b)? (6 ответов)
  131. как запросить у модели инф об элементе при переопределении метода data модели (4 ответов)
  132. создание делегата для QTableView на основе QTextEdit (8 ответов)
  133. Segmentation fault при использовании QSortFilterProxyModel и QTreeView (2 ответов)
  134. Вопрос архитектуры приложения (4 ответов)
  135. QTableView и QSqlTableModel в разных классах (4 ответов)
  136. QODBC+*.mdb+Linux (6 ответов)
  137. QTableView::flags (2 ответов)
  138. События мыши (9 ответов)
  139. Открытие в QAbstractItemView стандартного редактора (1 )
  140. Фильтр событий (3 ответов)
  141. QColumnView + QDirModel (0 ответов)
  142. Сделать QStandartItem невидимым (2 ответов)
  143. Поиск с помощью QSortFilterProxyModel (0 ответов)
  144. проблема сборки exe файла (3 ответов)
  145. setRelation оказался лишним? (5 ответов)
  146. просмотр таблицы с меняющимися данными, запоминание и выделение тек строки (14 ответов)
  147. Перехват нажатий клавиш в делегате (0 ответов)
  148. Лишние пробелы в QSqlQueryModel (2 ответов)
  149. QTable (4 ответов)
  150. Неверный QModelIndex (5 ответов)

Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.

PyQt6 — полное руководство для новичков

К старту курса по разработке на Python делимся детальным руководством по работе с современным PyQt. Чтобы читать было удобнее, мы объединили несколько статей в одну:

За подробностями приглашаем под кат.

Простое приложение Hello World! на Python и Qt6

PyQt — это библиотека Python для создания приложений с графическим интерфейсом с помощью инструментария Qt. Созданная в Riverbank Computing, PyQt является свободным ПО (по лицензии GPL) и разрабатывается с 1999 года. Последняя версия PyQt6 — на основе Qt 6 — выпущена в 2021 году, и библиотека продолжает обновляться. Это руководство можно также использовать для PySide2, PySide6 и PyQt5.

Сегодня используются две основные версии: PyQt5 на основе Qt5 и PyQt6 на основе Qt6. Обе почти полностью совместимы, за исключением импорта и отсутствия поддержки некоторых продвинутых модулей из Qt6. В PyQt6 вносятся изменения в работу пространств имён и флагов, но ими легко управлять. В этом руководстве мы узнаем, как использовать PyQt6 для создания настольных приложений.

Сначала создадим несколько простых окон на рабочем столе, чтобы убедиться, что PyQt работает, и разберём базовые понятия. Затем кратко изучим цикл событий и то, как он связан с программированием графического интерфейса на Python. В заключение поговорим о QMainWindow с полезными элементами интерфейса, такими как панели инструментов и меню. Подробно я расскажу о них в следующих руководствах.

Создание приложения
pip install pyqt6 # и на будущее pip install pyqt-tools

Сначала создадим новый файл Python с любым названием (например app.py) и сохраним его. Исходный код приложения показан ниже. Введите его полностью и постарайтесь не ошибиться. Если что-то напутаете, Python укажет, что именно:

from PyQt6.QtWidgets import QApplication, QWidget import sys # Только для доступа к аргументам командной строки # Приложению нужен один (и только один) экземпляр QApplication. # Передаём sys.argv, чтобы разрешить аргументы командной строки для приложения. # Если не будете использовать аргументы командной строки, QApplication([]) тоже работает app = QApplication(sys.argv) # Создаём виджет Qt — окно. window = QWidget() window.show() # Важно: окно по умолчанию скрыто. # Запускаем цикл событий. app.exec() # Приложение не доберётся сюда, пока вы не выйдете и цикл # событий не остановится.

Запускаем приложение из командной строки, как и любой скрипт Python:

python3 app.py

Выполнив его, мы увидим окно. В Qt автоматически создаётся окно с обычным оформлением, возможностью его перетаскивать и менять размер. То, что вы увидите, зависит от платформы, где этот пример выполняется. Вот как отображается это окно на Windows, macOS и Linux (Ubuntu):

Окно на Windows, macOS и Linux

Разбор кода

Пройдём код построчно, чтобы понять, что именно происходит. Сначала мы импортируем классы PyQt для приложения: здесь это обработчик приложения QApplication и базовый пустой виджет графического интерфейса QWidget (оба из модуля QtWidgets):

from PyQt6.QtWidgets import QApplication, QWidget

Основные модули для Qt: QtWidgets, QtGui и QtCore.

Возможен ещё from import * , но этот вид импорта обычно не приветствуется в Python. Дальше создаём экземпляр QApplication и передаём sys.arg (список Python с аргументами командной строки, передаваемыми приложению):

app = QApplication(sys.argv) 

Если не будете использовать аргументы командной строки для управления Qt, передайте пустой список:

app = QApplication([])

Затем создаём экземпляр QWidget, используя имя переменной window:

window = QWidget() window.show()

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

Виджеты без родительского элемента по умолчанию невидимы. Поэтому после создания объекта window необходимо всегда вызывать функцию .show(), чтобы сделать его видимым. .show() можно удалить, но тогда, запустив приложение, вы не сможете выйти из него!

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

Наконец, вызываем app.exec(), чтобы запустить цикл события.

Что такое «цикл событий»?

Прежде чем вывести окно на экран, разберём ключевые понятия, касающиеся организации приложений в мире Qt. Если вам уже знакомы циклы событий, можете пропустить эту часть статьи.

Основной элемент всех приложений в Qt — класс QApplication. Для работы каждому приложению нужен один — и только один — объект QApplication, который содержит цикл событий приложения. Это основной цикл, управляющий всем взаимодействием пользователя с графическим интерфейсом:

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

Класс QApplication содержит цикл событий Qt (нужен один экземпляр QApplication). Приложение ждёт в цикле событий новое событие, которое будет сгенерировано при выполнении действия. Всегда выполняется только один цикл событий.

QMainWindow

Итак, в Qt любые виджеты могут быть окнами. Например, если заменить QtWidget на QPushButton. В этом примере получается окно с одной нажимаемой кнопкой:

import sys from PyQt6.QtWidgets import QApplication, QPushButton app = QApplication(sys.argv) window = QPushButton("Push Me") window.show() app.exec()

Классно, но не очень полезно на самом деле: редко когда нужен пользовательский интерфейс, состоящий только из одного элемента управления. Зато возможность с помощью макетов вкладывать одни виджеты в другие позволяет создавать сложные пользовательские интерфейсы внутри пустого QWidget.

В Qt уже есть решение для окна — виджет QMainWindow, имеющий стандартные функции окна для использования в приложениях, который содержит панели инструментов, меню, строку состояния, закрепляемые виджеты и многое другое. Рассмотрим эти расширенные функции позже, а пока добавим в приложение простой, пустой QMainWindow:

import sys from PyQt6.QtWidgets import QApplication, QMainWindow app = QApplication(sys.argv) window = QMainWindow() window.show() # Запускаем цикл событий. app.exec()

Запускаем и видим главное окно. Точно такое же, как и раньше.

QMainWindow пока не очень интересный. Добавим контент. Чтобы сделать настраиваемое окно, лучше создать подкласс QMainWindow, а затем настроить окно в блоке __init__. Так окно станет независимым в плане поведения. Итак, добавляем подкласс QMainWindow — MainWindow:

import sys from PyQt6.QtCore import QSize, Qt from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton # Подкласс QMainWindow для настройки главного окна приложения class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") button = QPushButton("Press Me!") # Устанавливаем центральный виджет Window. self.setCentralWidget(button) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()

Для этого демо используем QPushButton. Основные виджеты Qt всегда импортируются из пространства имён QtWidgets, как и классы QMainWindow и QApplication. При использовании QMainWindow задействуем .setCentralWidget для размещения виджета (здесь виджет — QPushButton) в QMainWindow, по умолчанию он занимает всё окно. Как добавлять в окна несколько виджетов? Об этом поговорим рассмотрим в руководстве по макетам.

При создании подкласса из класса Qt, чтобы разрешить Qt настраивать объект, всегда нужно вызывать функцию super __init__.

В блоке __init__ сначала используем .setWindowTitle(), чтобы поменять заголовок главного окна. Затем добавляем первый виджет — QPushButton — в середину окна. Это один из основных виджетов Qt. При создании кнопки можно ввести текст, который будет на ней отображаться. Вызываем .setCentralWidget() в окне. Это специальная функция QMainWindow, которая позволяет установить виджет на середину окна.

Запускаем и снова видим окно, но на этот раз с виджетом QPushButton в центре. Нажатие кнопки ничего не даст — с этим мы разберёмся после:

QMainWindow с одной кнопкой QPushButton на Windows, macOS и Linux

Скоро мы подробно рассмотрим другие виджеты, но, если вам не терпится и хочется забежать вперёд, можете заглянуть в документацию QWidget. Попробуйте добавить различные виджеты в окно.

Изменение размеров окон и виджетов

Сейчас размер окна можно свободно поменять: щёлкните мышью на любой угол и перетаскивайте, меняя таким образом размер. Можно дать возможность пользователям самим менять размер приложений, а можно установить ограничения на минимальные или максимальные размеры или фиксированный размер окна.

В Qt размеры определяются с помощью объекта QSize. Он принимает параметры ширины и высоты. Например, так создаётся окно фиксированного размера 400 x 300 пикселей:

import sys from PyQt6.QtCore import QSize, Qt from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton # Подкласс QMainWindow для настройки главного окна приложения class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") button = QPushButton("Press Me!") self.setFixedSize(QSize(400, 300)) # Устанавливаем центральный виджет Window. self.setCentralWidget(button) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()

Запускаем и видим окно фиксированного размера. Поменять его размер не получится.

Окно фиксированного размера

Элемент управления maximize отключён на Windows и Linux. На macOS можно развернуть приложение на весь экран, но размер центрального виджета не изменится.

Кроме .setFixedSize() можно также вызвать .setMinimumSize() и .setMaximumSize(), чтобы установить минимальный и максимальный размеры соответственно. Попробуйте сами! Эти методы регулирования размеров работают в любом виджете. Продолжить изучение Python вы сможете на наших курсах:

  • Курс Python-разработчик
  • Профессия Fullstack-разработчик на Python
  • Курс «Python для веб-разработки»

А ещё вы можете приобрести книгу автора этих уроков или продолжить чтение.

Слоты и сигналы

Ранее мы рассмотрели классы QApplication и QMainWindow, цикл событий и добавили в окно простой виджет. А теперь изучим механизмы Qt для взаимодействия виджетов и окон друг с другом. В статью внесены изменения, связанные с PyQt6.

Мы создали окно и добавили в него простой виджет push button, но кнопка пока бесполезна. Нужно связать действие нажатия кнопки с происходящим. В Qt это делается с помощью сигналов и слотов или событий.

Сигналы — это уведомления, отправляемые виджетами, когда что-то происходит. Этим «чем-то» может быть что угодно — нажатие кнопки, изменение текста в поле ввода или изменение текста в окне. Многие сигналы инициируются в ответ на действия пользователя, но не только: в сигналах могут отправляться данные с дополнительным контекстом произошедшего.

Можно также писать собственные сигналы, их мы рассмотрим позже.

Слоты в Qt — это приёмники сигналов. Слотом в приложении на Python можно сделать любую функцию (или метод), просто подключив к нему сигнал. Принимающая функция получает данные, отправляемые ей в сигнале. У многих виджетов Qt есть встроенные слоты, а значит, виджеты можно подключать друг к другу напрямую.

Рассмотрим основные сигналы Qt и их использование для подключения виджетов в приложениях. Сохраните эту заготовку приложения в файле app.py:

import sys from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.setWindowTitle("My App") app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()

Сигналы QPushButton

Сейчас у нас есть QMainWindow с центральным виджетом QPushButton. Подключим эту кнопку к пользовательскому методу Python. Создадим простой настраиваемый слот the_button_was_clicked, принимающий сигнал clicked от QPushButton:

import sys from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") button = QPushButton("Press Me!") button.setCheckable(True) button.clicked.connect(self.the_button_was_clicked) # Устанавливаем центральный виджет Window. self.setCentralWidget(button) def the_button_was_clicked(self): print("Clicked!") app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()

Запускаем. Если нажать на кнопку, в консоли появится текст Clicked! («Нажата!»):

Clicked! Clicked! Clicked! Clicked! 
Получение данных

В сигналах может отправляться дополнительная информация о произошедшем. И сигнал .clicked — не исключение: с его помощью сообщается о нажатом (или переключенном) состоянии кнопки. Для обычных кнопок это значение всегда False, поэтому первый слот проигнорировал эти данные. Включим возможность нажатия кнопки, чтобы увидеть этот эффект. Ниже добавляется второй слот и выводится состояние нажатия:

class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") button = QPushButton("Press Me!") button.setCheckable(True) button.clicked.connect(self.the_button_was_clicked) button.clicked.connect(self.the_button_was_toggled) self.setCentralWidget(button) def the_button_was_clicked(self): print("Clicked!") def the_button_was_toggled(self, checked): print("Checked?", checked) 

Запускаем! Если нажать на кнопку, она подсветится и станет checked («Нажатой»). Чтобы отключить её, нажимаем ещё раз. Найдите состояние нажатия в консоли:

Clicked! Checked? True Clicked! Checked? False Clicked! Checked? True Clicked! Checked? False Clicked! Checked? True 

К сигналу подключается сколько угодно слотов, в которых можно реагировать сразу на несколько версий сигналов.

Хранение данных

Текущее состояние виджета на Python часто хранят в переменной, что позволяет работать со значениями без доступа к исходному виджету. Причём для их хранения используются отдельные переменные или словарь. В следующем примере сохраняем значение кнопки checked («Нажата») в переменной button_is_checked в self:

class MainWindow(QMainWindow): def __init__(self): super().__init__() self.button_is_checked = True self.setWindowTitle("My App") button = QPushButton("Press Me!") button.setCheckable(True) button.clicked.connect(self.the_button_was_toggled) button.setChecked(self.button_is_checked) self.setCentralWidget(button) def the_button_was_toggled(self, checked): self.button_is_checked = checked print(self.button_is_checked) 

Сначала устанавливаем переменной значение по умолчанию True, а затем используем это значение, чтобы установить исходное состояние виджета. Когда состояние виджета меняется, получаем сигнал и соответственно обновляем переменную.

Эта же схема применима к любым виджетам PyQt. Если в виджете нет сигнала, которым отправляется текущее состояние, нужно получить значение из виджета прямо в обработчике. Например, здесь мы проверяем состояние checked («Нажата») в нажатом обработчике:

class MainWindow(QMainWindow): def __init__(self): super().__init__() self.button_is_checked = True self.setWindowTitle("My App") self.button = QPushButton("Press Me!") self.button.setCheckable(True) self.button.released.connect(self.the_button_was_released) self.button.setChecked(self.button_is_checked) self.setCentralWidget(self.button) def the_button_was_released(self): self.button_is_checked = self.button.isChecked() print(self.button_is_checked) 

Сохраним ссылку на кнопку в self, чтобы получить к ней доступ в слоте.

Сигнал released срабатывает, когда кнопка отпускается, при этом состояние нажатия не отправляется. Его получают из кнопки в обработчике, используя .isChecked().

Изменение интерфейса

Мы уже видели, как принимаются сигналы и выводятся на консоль результаты. Но что происходит с интерфейсом, когда нажимают на кнопку? Обновим метод слота, чтобы изменить кнопку, поменяв текст, отключив её и сделав её недоступной. И отключим пока состояние, допускающее нажатие:

class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") self.button = QPushButton("Press Me!") self.button.clicked.connect(self.the_button_was_clicked) self.setCentralWidget(self.button) def the_button_was_clicked(self): self.button.setText("You already clicked me.") self.button.setEnabled(False) # Также меняем заголовок окна. self.setWindowTitle("My Oneshot App") 

Снова нужен доступ к кнопке в методе the_button_was_clicked, поэтому сохраняем ссылку на неё в self. Чтобы поменять текст кнопки, передаём str в .setText(). Чтобы отключить кнопку, вызываем .setEnabled() с аргументом False. И запускаем программу. Если нажать на кнопку, текст изменится и кнопка станет недоступной.

В методах слота можно не только менять кнопку, которая активирует сигнал, но и делать всё что угодно. Например, поменять заголовок окна, добавив в метод the_button_was_clicked эту строку:

self.setWindowTitle("A new window title")

Большинство виджетов, в том числе QMainWindow, имеют свои сигналы. В следующем, более сложном примере подключим сигнал .windowTitleChanged в QMainWindow к пользовательскому методу слота. А также сделаем для этого слота новый заголовок окна:

from PyQt6.QtWidgets import QApplication, QMainWindow, QPushButton import sys from random import choice window_titles = [ 'My App', 'My App', 'Still My App', 'Still My App', 'What on earth', 'What on earth', 'This is surprising', 'This is surprising', 'Something went wrong' ] class MainWindow(QMainWindow): def __init__(self): super().__init__() self.n_times_clicked = 0 self.setWindowTitle("My App") self.button = QPushButton("Press Me!") self.button.clicked.connect(self.the_button_was_clicked) self.windowTitleChanged.connect(self.the_window_title_changed) # Устанавливаем центральный виджет Window. self.setCentralWidget(self.button) def the_button_was_clicked(self): print("Clicked.") new_window_title = choice(window_titles) print("Setting title: %s" % new_window_title) self.setWindowTitle(new_window_title) def the_window_title_changed(self, window_title): print("Window title changed: %s" % window_title) if window_title == 'Something went wrong': self.button.setDisabled(True) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()

Сначала создаём список заголовков окна и выбираем один из них наугад, используя встроенную функцию Python random.choice(). Подключаем пользовательский метод слота the_window_title_changed к сигналу окна .windowTitleChanged.

При нажатии на кнопку заголовок окна случайным образом изменится. Если новый заголовок окна изменится на Something went wrong («Что-то пошло не так»), кнопка отключится.

Запускаем! Нажимайте на кнопку, пока заголовок не изменится на Something went wrong. В этом примере стоит обратить внимание вот на что:

  1. Сигнал windowTitleChanged при установке заголовка окна выдаётся не всегда. Он срабатывает, только если новый заголовок отличается от предыдущего: если один и тот же заголовок устанавливается несколько раз, сигнал срабатывает только в первый раз. Чтобы избежать неожиданностей, важно перепроверять условия срабатывания сигналов при их использовании в приложении.
  2. С помощью сигналов создаются цепочки. Одно событие — нажатие кнопки — может привести к тому, что поочерёдно произойдут другие. Эти последующие эффекты отделены от того, что их вызвало. Они возникают согласно простым правилам. И это отделение эффектов от их триггеров — один из ключевых принципов, которые учитываются при создании приложений с графическим интерфейсом. Возвращаться к этому будем на протяжении всего курса.

Мы рассмотрели сигналы и слоты, показали простые сигналы и их использование для передачи данных и состояния в приложении. Теперь переходим к виджетам Qt, которые будут использоваться в приложениях вместе с сигналами.

Подключение виджетов друг к другу напрямую

Мы уже видели примеры подключения сигналов виджетов к методам Python. Когда сигнал из виджета срабатывает, вызывается метод Python, из сигнала он получает данные. Но для обработки сигналов не всегда нужна функция Python — можно подключать виджеты друг к другу напрямую.

Добавим в окно виджеты QLineEdit и QLabel. В __init__ для окна и подключим сигнал редактирования строки .textChanged к методу .setText в QLabel. Когда в QLineEdit меняется текст, он сразу будет поступать в QLabel (в метод .setText):

from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QVBoxLayout, QWidget import sys class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("My App") self.label = QLabel() self.input = QLineEdit() self.input.textChanged.connect(self.label.setText) layout = QVBoxLayout() layout.addWidget(self.input) layout.addWidget(self.label) container = QWidget() container.setLayout(layout) # Устанавливаем центральный виджет Window. self.setCentralWidget(container) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()

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

Введите текст в верхнем поле — он сразу появится в виде метки.

У большинства виджетов Qt есть доступные слоты, к которым подключается любой сигнал, возврощающий тот же тип, что он принимает. В документации по виджетам, в разделе Public Slots («Общедоступные слоты»), имеются слоты для каждого виджета. Посмотрите документацию для QLabel.

События

Любое взаимодействие пользователя с приложением Qt — это событие. Есть много типов событий, каждое из которых — это отдельный тип взаимодействия. В Qt события представлены объектами событий, в которые упакована информация о произошедшем. События передаются определённым обработчикам событий в виджете, где произошло взаимодействие.

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

QMouseEvent — одно из основных событий, получаемых виджетами. События QMouseEvent создаются для каждого отдельного нажатия кнопки мыши и её перемещения в виджете. Вот обработчики событий мыши:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *