Russian Qt Forum
Январь 24, 2017, 22:12 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало Форум WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  
  Просмотр сообщений
Страниц: [1] 2 3 ... 109
1  Qt / Уроки и статьи / Написание пользовательских делегатов для таблицы (python3 Qt4/Qt5) : Январь 23, 2017, 09:09
Я расскажу как они делаются. Хоть код будет на python, то разобраться в нем не составит труда -- т.к. в нем используется Qt и отличия будут только в синтаксисе, а он в python очень понятный. Попросили меня в теме приложить пример.
В конце можно будет скачать архив с скриптом.

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

Делегаты мы используем, если хотим сделать что-то нестандартное, например из официальной документации Star Delegate Example



Выглядит очень здорово Улыбающийся

А вот так будет выглядеть делегаты, которые я опишу в этом примере:




Теперь к делу.

Делегаты создаются наследование класса QStyledItemDelegate и переопределением определенных методов.
Для текущего примера будет переопределен метод paint и в нем реализована своя логика рисования. А рисовать будем то, что окажется в Qt::DecorationRole (это иконка в ячейке).

А чтобы делегат начал использоваться его нужно установить для этого у базового класса представлений QAbstractItemView есть методы: setIndexWidget, setItemDelegate, setItemDelegateForColumn и setItemDelegateForRow.
Первый -- установка делегата в выбранную ячейку, второй -- для всего представлений (список, таблица, дерево, и т.п.) и последнии -- для выбранных строк и столбцов.

Я опишу подробно делегат для второго столбца из примера (Delegate v1), потому что разница между приведенными делегатами почти нулевая.

Код
Python
class MyDelegate_1(QStyledItemDelegate):
   def paint(self, painter, option, index):
       # Получение ссылки на изображение в иконке, если его нет, тогда вызывается родительский метод рисования
       img = index.model().data(index, Qt.DecorationRole)
       if img is None:
           super().paint(painter, option, index)
           return
 
       # Получение размеров ячейки и растягивание иконки на размер ячейки
       rect = option.rect
       w, h = rect.size().width(), rect.size().height()
       img = img.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)
 
       painter.drawPixmap(rect, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       # Обработка при выделении ячейки делегата
       # Рисуем выделение полупрозрачным чтобы было видно нарисованное ранее
       if item_option.state & QStyle.State_Selected:
           # Получаем цвет, используемый при выделении ячеек
           color = item_option.palette.color(QPalette.Highlight)
 
           # Делаем его полупрозрачным
           color.setAlpha(180)
 
           # Сохранение состояния рисовальщика, изменение состояния, рисование и восстановление старого состояния
           painter.save()
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
           painter.restore()
 
       # Если хотим что-то дорисовать (например текст)
       # super().paint(painter, option, index)
 

Вообще, этот код я брал и адаптировал из другой программы на с++, которую делал.


Весь код, для тех кто не может скачать:
Код
Python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
 
__author__ = 'ipetrash'
 
 
try:
   from PyQt5.QtWidgets import *
   from PyQt5.QtGui import *
   from PyQt5.QtCore import *
except:
   from PyQt4.QtCore import *
   from PyQt4.QtGui import *
 
 
# Для отлова всех исключений, которые в слотах Qt могут "затеряться" и привести к тихому падению
def log_uncaught_exceptions(ex_cls, ex, tb):
   text = '{}: {}:\n'.format(ex_cls.__name__, ex)
   import traceback
   text += ''.join(traceback.format_tb(tb))
 
   print('Error: ', text)
   QMessageBox.critical(None, 'Error', text)
   quit()
 
 
import sys
sys.excepthook = log_uncaught_exceptions
 
 
def create_item(img):
   item = QTableWidgetItem()
   item.setData(Qt.DecorationRole, img)
 
   return item
 
 
class MyDelegate_1(QStyledItemDelegate):
   def paint(self, painter, option, index):
       img = index.model().data(index, Qt.DecorationRole)
       if img is None:
           super().paint(painter, option, index)
           return
 
       rect = option.rect
       w, h = rect.size().width(), rect.size().height()
       img = img.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)
 
       painter.drawPixmap(rect, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       # Обработка при выделении ячейки делегата
       # Рисуем выделение полупрозрачным чтобы было видно нарисованное ранее
       if item_option.state & QStyle.State_Selected:
           color = item_option.palette.color(QPalette.Highlight)
           color.setAlpha(180)
 
           painter.save()
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
           painter.restore()
 
       # Если хотим что-то дорисовать (например текст)
       # super().paint(painter, option, index)
 
 
class MyDelegate_2(QStyledItemDelegate):
   def paint(self, painter, option, index):
       img = index.model().data(index, Qt.DecorationRole)
       if img is None:
           super().paint(painter, option, index)
           return
 
       rect = option.rect
       x, y = rect.x(), rect.y()
       painter.drawPixmap(x, y, img)
 
       painter.drawPixmap(x + 16, y, img)
       painter.drawPixmap(x + 32, y, img)
       painter.drawPixmap(x + 48, y, img)
       painter.drawPixmap(x + 64, y, img)
       painter.drawPixmap(x + 80, y, img)
 
       painter.drawPixmap(x, y + 16, img)
       painter.drawPixmap(x + 16, y + 16, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       # Обработка при выделении ячейки делегата
       # Рисуем выделение полупрозрачным чтобы было видно нарисованное ранее
       if item_option.state & QStyle.State_Selected:
           color = item_option.palette.color(QPalette.Highlight)
           color.setAlpha(180)
 
           painter.save()
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
           painter.restore()
 
       # # Если хотим что-то дорисовать (например текст)
       # super().paint(painter, option, index)
 
 
if __name__ == '__main__':
   app = QApplication([])
 
   table = QTableWidget()
   table.setSelectionBehavior(QTableView.SelectRows)
   table.show()
   table.resize(400, 200)
 
   headers = ['Normal', 'Delegate v1', 'Delegate v1 (without img)', 'Delegate v2']
   table.setColumnCount(len(headers))
   table.setHorizontalHeaderLabels(headers)
   table.setRowCount(3)
   table.verticalHeader().hide()
 
   pix_1 = QPixmap('favicon_google.png')
   pix_2 = QPixmap('favicon_prog_org.png')
   pix_3 = QPixmap('favicon_google_tr.png')
 
   for col in range(table.columnCount()):
       if col == 2:
           table.setItem(1, col, QTableWidgetItem())
       else:
           table.setItem(0, col, create_item(pix_1))
           table.setItem(1, col, create_item(pix_2))
           table.setItem(2, col, create_item(pix_3))
 
   delegate_1 = MyDelegate_1()
   delegate_2 = MyDelegate_2()
 
   table.setItemDelegateForColumn(1, delegate_1)
   table.setItemDelegateForColumn(2, delegate_1)
   table.setItemDelegateForColumn(3, delegate_2)
 
   app.exec()
 
 
2  Программирование / Python / Re: QTableWidgetItem : Январь 22, 2017, 23:24
Изначально пустые ячейки
Сделал примерно как ты сказал
Код
Python
class MyDelegate(QStyledItemDelegate):
   def paint(self, painter, option, index):
       painter.save()
 
       rect = option.rect
       img = index.model().data(index, Qt.DecorationRole)
       w, h = rect.size().width(), rect.size().height()
       if img is None:
           super().paint(painter, option, index)
           #painter(exit())
       else:
           img = img.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)
           painter.drawPixmap(rect, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       #Для полупрозрачности выделения
       if item_option.state & QStyle.State_Selected:
           color = item_option.palette.color(QPalette.Highlight)
           color.setAlpha(160)
 
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
 
           painter.restore()
Уже меньше ругается  Улыбающийся
Пишет QPainter::end: Painter ended with 380 saved states

Я бы сделал так:
Код
Python
   def paint(self, painter, option, index):
       img = index.model().data(index, Qt.DecorationRole)
       if img is None:
           super().paint(painter, option, index)
           return
 
       rect = option.rect
       w, h = rect.size().width(), rect.size().height()
       img = img.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)
 
       painter.drawPixmap(rect, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       # Обработка при выделении ячейки делегата
       # Рисуем выделение полупрозрачным чтобы было видно нарисованное ранее
       if item_option.state & QStyle.State_Selected:
           color = item_option.palette.color(QPalette.Highlight)
           color.setAlpha(180)
 
           painter.save()
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
           painter.restore()
 
 
       # Если хотим что-то дорисовать (например текст)
       # super().paint(painter, option, index)
 


Обновил тот код и сообщение с примером
3  Программирование / Python / Re: QTableWidgetItem : Январь 22, 2017, 19:42
Все работает хорошо спасибо.
Только не работает выделение ячейки по щелчку мыши(ну это мелочи).
Хотя выдает ошибку,
img = img.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)
AttributeError: 'NoneType' object has no attribute 'scaled'

Если вы код не меняли все будет работать Улыбающийся

img берется из Qt.DecorationRole:
Код
Python
img = index.model().data(index, Qt.DecorationRole)

Если делегат используется для ячеек без картинки в Qt.DecorationRole, то нужно тогда в делегат добавить проверку на наличие значения в img,
например если img is None, тогда вызываем родительский метод отрисовки super().paint(painter, option, index) и выходим из функции рисования

4  Программирование / Python / Re: QTableWidgetItem : Январь 20, 2017, 13:36
Набросал я простенький пример использования делегата для отрисовки.

Ну и весь код:
Код
Python
try:
   from PyQt5.QtWidgets import *
   from PyQt5.QtGui import *
   from PyQt5.QtCore import *
except:
   from PyQt4.QtCore import *
   from PyQt4.QtGui import *
 
 
# Для отлова всех исключений, которые в слотах Qt могут "затеряться" и привести к тихому падению
def log_uncaught_exceptions(ex_cls, ex, tb):
   text = '{}: {}:\n'.format(ex_cls.__name__, ex)
   import traceback
   text += ''.join(traceback.format_tb(tb))
 
   print('Error: ', text)
   QMessageBox.critical(None, 'Error', text)
   quit()
 
 
import sys
sys.excepthook = log_uncaught_exceptions
 
 
def create_item(img):
   item = QTableWidgetItem()
   item.setData(Qt.DecorationRole, img)
 
   return item
 
 
class MyDelegate_1(QStyledItemDelegate):
   def paint(self, painter, option, index):
       img = index.model().data(index, Qt.DecorationRole)
       if img is None:
           super().paint(painter, option, index)
           return
 
       rect = option.rect
       w, h = rect.size().width(), rect.size().height()
       img = img.scaled(w, h, Qt.KeepAspectRatio, Qt.SmoothTransformation)
 
       painter.drawPixmap(rect, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       # Обработка при выделении ячейки делегата
       # Рисуем выделение полупрозрачным чтобы было видно нарисованное ранее
       if item_option.state & QStyle.State_Selected:
           color = item_option.palette.color(QPalette.Highlight)
           color.setAlpha(180)
 
           painter.save()
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
           painter.restore()
 
       # Если хотим что-то дорисовать (например текст)
       # super().paint(painter, option, index)
 
 
class MyDelegate_2(QStyledItemDelegate):
   def paint(self, painter, option, index):
       img = index.model().data(index, Qt.DecorationRole)
       if img is None:
           super().paint(painter, option, index)
           return
 
       rect = option.rect
       x, y = rect.x(), rect.y()
       painter.drawPixmap(x, y, img)
 
       painter.drawPixmap(x + 16, y, img)
       painter.drawPixmap(x + 32, y, img)
       painter.drawPixmap(x + 48, y, img)
       painter.drawPixmap(x + 64, y, img)
       painter.drawPixmap(x + 80, y, img)
 
       painter.drawPixmap(x, y + 16, img)
       painter.drawPixmap(x + 16, y + 16, img)
 
       item_option = QStyleOptionViewItem(option)
       self.initStyleOption(item_option, index)
 
       # Обработка при выделении ячейки делегата
       # Рисуем выделение полупрозрачным чтобы было видно нарисованное ранее
       if item_option.state & QStyle.State_Selected:
           color = item_option.palette.color(QPalette.Highlight)
           color.setAlpha(180)
 
           painter.save()
           painter.setPen(Qt.NoPen)
           painter.setBrush(color)
           painter.drawRect(rect)
           painter.restore()
 
       # # Если хотим что-то дорисовать (например текст)
       # super().paint(painter, option, index)
 
 
if __name__ == '__main__':
   app = QApplication([])
 
   table = QTableWidget()
   table.setSelectionBehavior(QTableView.SelectRows)
   table.show()
   table.resize(400, 200)
 
   headers = ['Normal', 'Delegate v1', 'Delegate v1 (without img)', 'Delegate v2']
   table.setColumnCount(len(headers))
   table.setHorizontalHeaderLabels(headers)
   table.setRowCount(3)
   table.verticalHeader().hide()
 
   pix_1 = QPixmap('favicon_google.png')
   pix_2 = QPixmap('favicon_prog_org.png')
   pix_3 = QPixmap('favicon_google_tr.png')
 
   for col in range(table.columnCount()):
       if col == 2:
           table.setItem(1, col, QTableWidgetItem())
       else:
           table.setItem(0, col, create_item(pix_1))
           table.setItem(1, col, create_item(pix_2))
           table.setItem(2, col, create_item(pix_3))
 
   delegate_1 = MyDelegate_1()
   delegate_2 = MyDelegate_2()
 
   table.setItemDelegateForColumn(1, delegate_1)
   table.setItemDelegateForColumn(2, delegate_1)
   table.setItemDelegateForColumn(3, delegate_2)
 
   app.exec()
 
 
 

Выглядит вот так (первый столбец обычный, остальные имеют делегаты):

5  Разное / Говорилка / Re: Все программеры на дельфях такие неадекватные? : Январь 20, 2017, 08:34
Меня удивляет что на делфи что-то еще делают.
На стековерфлоу каждый день появляются новые вопросы по ней Улыбающийся
6  Программирование / Python / Re: QTableWidgetItem : Январь 18, 2017, 16:11
Так ведь на с++ и питоне один и тот же Qt
самое большое различие -- способ коннекта, остальное -- различие языков, если вы пользуетесь IDE PyCharm, то вам проще писать код

Попробуйте найти пример делегата на с++ и просто перепишите код на питон.
Можете тут вопросы задавать, на питоне я вот уже почти 3 года что-нибудь для себя пишу смогу подсказать

7  Программирование / Python / Re: QTableWidgetItem : Январь 18, 2017, 15:15
Widget устанавливается во view, а роль задаётся в модели через QAbstractItemModel::setData(...).
Есть пример где это реализовано?, неужели никто картинки в таблицу не вставляет? =) Я имею ввиду просто вставить картинку с DecorationRole не иконку.

Типа такого? Смеющийся

8  Программирование / Python / Re: QTableWidgetItem : Январь 17, 2017, 12:08
Я хочу без делегата обойтись

Тогда пишите свою таблицу Улыбающийся
9  Программирование / Python / Re: QTableWidgetItem : Январь 17, 2017, 08:33
Для этого используются делегаты. Они рисуют ячейки
Т.е. вам нужно будет создать делегат, в его методе рисования собственно и нарисовать вашу иконку.
Когда-то делал подобное // В корне проекта можно будет увидеть скрины
10  Qt / Вопросы новичков / Re: Привязать меню к QToolButton : Январь 16, 2017, 13:10
Или сделать как тут: "Ribbon? Это просто! или Работаем с каскадными таблицами стилей (CSS) в Qt"

Ну и результат:



11  Qt / Общие вопросы / Re: QTCPSocket в отдельном потоке. : Январь 11, 2017, 09:35
Еще советую не наследоваться от QThread, а делать moveToThread. На форуме есть обсуждение данного совета со ссылками.

В доке написано что можно и так, и так Улыбающийся
http://doc.qt.io/qt-5/qthread.html#details

// You can use worker objects by moving them to the thread using QObject::moveToThread().
Код
C++ (Qt)
class Worker : public QObject
{
   Q_OBJECT
 
public slots:
   void doWork(const QString &parameter) {
       QString result;
       /* ... here is the expensive or blocking operation ... */
       emit resultReady(result);
   }
 
signals:
   void resultReady(const QString &result);
};
 
class Controller : public QObject
{
   Q_OBJECT
   QThread workerThread;
public:
   Controller() {
       Worker *worker = new Worker;
       worker->moveToThread(&workerThread);
       connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
       connect(this, &Controller::operate, worker, &Worker::doWork);
       connect(worker, &Worker::resultReady, this, &Controller::handleResults);
       workerThread.start();
   }
   ~Controller() {
       workerThread.quit();
       workerThread.wait();
   }
public slots:
   void handleResults(const QString &);
signals:
   void operate(const QString &);
};
 

// Another way to make code run in a separate thread, is to subclass QThread and reimplement run(). For example:
Код
C++ (Qt)
class WorkerThread : public QThread
{
   Q_OBJECT
   void run() Q_DECL_OVERRIDE {
       QString result;
       /* ... here is the expensive or blocking operation ... */
       emit resultReady(result);
   }
signals:
   void resultReady(const QString &s);
};
 
void MyObject::startWorkInAThread()
{
   WorkerThread *workerThread = new WorkerThread(this);
   connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
   connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
   workerThread->start();
}
 
12  Qt / Установка, сборка, отладка, тестирование / Re: Не запускается тестовое приложение на эмуляторе : Январь 01, 2017, 21:20
Похоже, проблема в эмуляторе андроида
С андроид студией и visual studio с xamarin была такая же фигня и предварительный запуск эмулятора помогал
13  Qt / Установка, сборка, отладка, тестирование / Re: Кракозябры в окне ошибок нового Qt Creator и MSVC2015 : Декабрь 31, 2016, 00:39
переименовать файл:
%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\bin\1049\clui.dll
в какой-нибудь clui.dll.bak
или удалить


выхлоп компилятора студии станет английским.

Да-да-да! Улыбающийся
После переименования clui.dll в папке 1049, компилятор снова ругается на английском, а не на эльфийском Смеющийся
14  Qt / Установка, сборка, отладка, тестирование / Re: Кракозябры в окне ошибок нового Qt Creator и MSVC2015 : Декабрь 30, 2016, 19:45
Мне на такой вопрос как-то ответили: не выпендривайся и ставь английскую студию.

Дык, у меня вроде бы как раз и англоязычная студия: http://www.prog.org.ru/index.php?topic=30878.msg228463#msg228463
Возможно, при установке я поставил русскую, а потом сменил язык на английский... Непонимающий

Ок, попробую переустановить студию
15  Qt / Установка, сборка, отладка, тестирование / Re: Кракозябры в окне ошибок нового Qt Creator и MSVC2015 : Декабрь 30, 2016, 19:08
А вот при использовании mingw выхлоп компилятора нормальный.

Интересно, у тех кто использует компилятор студии такие проблемы?
Страниц: [1] 2 3 ... 109
Страница сгенерирована за 0.209 секунд. Запросов: 23.