Найти - Пользователи
Полная версия: PyQt обновление объектов
Начало » GUI » PyQt обновление объектов
1 2
Обедающий философ
Здравствуйте!

Есть у меня QLabel, а в ней периодически меняется текст. Однако она остаётся прежнего размера, посему текст порой в неё не вписывается. Как сделать, чтобы её размер менялся автоматически?

Также у меня есть QGraphicsItem, который я также хочу, чтобы периодически обновлялся. И он обновляется, вот только не всегда. Я даже пробовал делать QGraphicsView.repaint(), но это не помогло. Как мне добиться желаемого?

Заранее благодарен.
Slon
C QLabel можно сделать len() на строку с текстом, и потом обновлять размер вместе с воодом текста.
Обедающий философ
Slon
C QLabel можно сделать len() на строку с текстом, и потом обновлять размер вместе с воодом текста.
Ничего не понял.

C QLabel я теперь делаю self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum) каждый раз, когда обновляю строку. Работает заметно лучше, нежели было, но иногда отчего-то не приводит к должному результату.

С QGraphicsItem так и не придумал ничего.

Также отчего-то на одном компьютере моё творение летает (экран обновляется где-то за 0,1 секунды), на другом - та же операция занимает около трёх секунд. При том, что на первом компе видеокарта geforce 240, а на втором - quadro 4000. На обоих ubuntu 11.04.
dartNNN
Обсуждение сферического коня В Вакууме. Покажите хоть какой-нибудь код:) Скорость зависит не только от Видеокарты но и от других компонент. Непостоянство работы говорит 0 неявной ошибке.
Обедающий философ
Ну вот такой приблизительно код.

class AgentLabel(QtGui.QLabel):

def __init__(self):
QtGui.QLabel.__init__(self, "")
self.setStyleSheet("* {background-color: transparent;}")
self.setMouseTracking(True)

...................

def update(self, a):
self.agent = a
self.setText(agent_brief.get_colored(self.agent))
self.show()
self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum) # чтобы размер изменился..


class LabelList:

def __init__(self, scene):
self.scene = scene
self.labels = [self.scene.addWidget(AgentLabel())] # чтобы не было случая с пустым списком
self.hide()

def setlabel(self, y, x, a):
l = self.labels.pop(0)
self.labels.append(l)
if l.isVisible():
l = self.scene.addWidget(AgentLabel())
self.labels.append(l)
l.setPos(x, y)
l.widget().update(a)
return l

def hide(self):
for l in self.labels:
l.hide()

class CellItem(QtGui.QGraphicsItem):

bgcolor = QtGui.QColor(0xeeeeee)
bordercolor = QtGui.QColor(0xaaaaaa)
popcolor = QtGui.QColor(0x7777aa)
foodcolor = QtGui.QColor(0x33cc33)
height_coef = 0.2

def __init__(self, y, x, h, w, scene, labels, cell):
QtGui.QGraphicsItem.__init__(self)
self.x = x
self.y = y
self.setPos(x, y)
self.width = w
self.height = h
self.rect = QtCore.QRectF(0, 0, w, h)
self.scene = scene
self.labels = labels
self.cell = cell

self.setZValue(-1)
self.scene.addItem(self)

def update(self):
alist = agent_list(self.cell)
if len(alist)>0:
dy = self.height/len(alist)
xl = self.x + self.width*0.1
yl = self.y
for a in alist:
l = self.labels.setlabel(yl, xl, a)
yl += self.height*self.height_coef

def paint(self, painter, option, widget=None):
painter.setBrush(self.bgcolor)
painter.setPen(self.bordercolor)
painter.drawRect(1, 1, self.width, self.height)
if self.cell.agent_n>0:
painter.setPen(self.popcolor)
painter.drawText(self.width*0.8, 0+self.height*0.2, str(self.cell.agent_n))
if self.cell.food_present>0:
painter.setPen(self.foodcolor)
painter.drawText(self.width*0.8, 0+self.height*0.9, str(self.cell.food_present))

def boundingRect(self):
return self.rect

class DetailedGui(QtGui.QWidget):

left_column_width = 100
colum_width = 100
row_height = 100
map_rect = [0, 0, 10, 10]

def __init__(self, *args):
QtGui.QWidget.__init__(self,*args)
self.setWindowTitle(u"Detailed map")

self.stats = agent_brief

self.infolabel = QtGui.QLabel("")
self.maplabel = QtGui.QTextEdit(self.stats.get_detailed_map(*self.map_rect))
self.maplabel.document().setDefaultStyleSheet(self.stylestring)

self.scene = QtGui.QGraphicsScene(self)
self.view = QtGui.QGraphicsView(self.scene)

self.labels = LabelList(self.scene)

self.init_map()

self.layout1 = QtGui.QVBoxLayout()
self.layout1.addWidget(self.infolabel)

self.layout0 = QtGui.QHBoxLayout(self)
self.layout0.addLayout(self.layout1)
self.layout0.addWidget(self.view)

def init_map(self):
self.cells = []
x0 = self.map_rect[0]
y0 = self.map_rect[1]
x1 = self.map_rect[2]
y1 = self.map_rect[3]
w = self.colum_width
h = self.row_height
for y in xrange(y0, y1):
for x in xrange(x0, x1):
c = world.cells[y][x]
self.cells.append(CellItem((y-y0)*h, (x-x0)*w, h, w, self.scene, self.labels, c)) #(self, y, x, h, w, scene, cell)

................................

def redraw_map(self):
self.labels.hide()
for c in self.cells:
c.update()
#self.view.repaint()
Вопщем смысл в следующем. Есть QGraphicsScene/QGraphicsView, и в нём собственно имеют место быть некоторое количество объектов типов QLabel и CellItem(QtGui.QGraphicsItem). Клетки всегда одни и те же, а вот лабелы служат для представления объектов (агентов), которых каждый раз переменное количество и они каждый раз в новом месте. DetailedGui.labels (класса LabelList) - это собственно пул лабелов, каковые каждый раз прячутся и извлекаются по мере надобности, а когда их не хватает, то создаются новые.

На каждом шаге вызывается функция DetailedGui.redraw_map(). Она сначала прячет лабелы, а затем вызывает CellItem.update(), каковой вызывает AgentLabel.update() для каждого из агентов, находящихся в оной клетке. А вот функция CellItem.paint(), каковая собственно перерисовывает клетку, вызывается, видимо, каким-то мистическим глубинным механизмом. И чтобы она принудительно перерисовывалась каждый раз, я вижу два варианта - либо вызывать CellItem.paint() самому (это я не знаю как), либо банально весь нужный текст также засовывать в лабелы. Второе, конечно, проще, но я ещё хочу рисовать линии.
dartNNN
Признаюсь разобраться в коде мне толком не удалось. Скажу сразу конкретных рецептов я дать не могу. Но считаю, что код можно переработать в более-менее приемлемый, что в конечном итоге должно привести к более полному понимаю механизмов отрисовки элементов и самой проблемы, да и вообще это полезно для развития.
Итак, если вы со мной согласны и у вас достаточно времени, то…
self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum) лучше делать в конструкторе, т.к. она задает политику обновления размера.
цель метода setlabel в LabelList для меня осталась загадкой (чутьем чую, что можно сделать проще)
Главный вопрос: зачем вообще нужны QGraphicsView и QGraphicsItem? Точнее почему именно они? Насколько я понимаю, у вас динамическое добавление/удаление Label? Для этих целей не обязательно использовать QGraphicsView (он предназначен как раз для рисования линий, кружочков, квадратиков:))
И если вас не затруднит изложите (переработайте) модель предметной области (задачи) в терминах объектов. С ООП знакомы? Тогда будет проще совместить вашу объектную модель с (любым) объектным фреймворком.
Как я вижу есть объекты Агенты (которые должны быть представлены на форме, в вашем случае с помошью Label) и совершенно неведомое (для меня) их взаимодействие…
Обедающий философ
dartNNN
self.setSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Minimum) лучше делать в конструкторе, т.к. она задает политику обновления размера.
Я так пробовал - не получается должного эффекта.

dartNNN
цель метода setlabel в LabelList для меня осталась загадкой (чутьем чую, что можно сделать проще)
Всё очень просто. Сначала извлекается из пула незанятый лабел, а коли они все заняты (о чём свидетельствует то, что извлечённый лабел видимый) - создаётся ещё один и снова помещается в пул. А затем он перемещается на нужное место, снабжается нужным текстом и делается видимым (две последние операции производятся в AgentLabel.update()).

dartNNN
Главный вопрос: зачем вообще нужны QGraphicsView и QGraphicsItem? Точнее почему именно они? Насколько я понимаю, у вас динамическое добавление/удаление Label? Для этих целей не обязательно использовать QGraphicsView (он предназначен как раз для рисования линий, кружочков, квадратиков)
Вот этот вопрос меня тоже интересует. Только я не смог найти примеров, как это сделать без QGraphicsView.

dartNNN
Насколько я понимаю, у вас динамическое добавление/удаление Label?
Не только, ещё у меня надо рисовать клетки и линии (причём линии также надо перерисовывать каждый раз).

dartNNN
И если вас не затруднит изложите (переработайте) модель предметной области (задачи) в терминах объектов. С ООП знакомы? Тогда будет проще совместить вашу объектную модель с (любым) объектным фреймворком.
А у меня разве нет объектов? Что я делаю не так? Объединять в одном объекте механику и отрисовку не буду, даже не уговаривайте.

dartNNN
Как я вижу есть объекты Агенты (которые должны быть представлены на форме, в вашем случае с помошью Label) и совершенно неведомое (для меня) их взаимодействие…
Ну их взаимодействие в данном случае не столь важно. Важно то, что они периодически перемещаются, появляются и исчезают.

А вообще вот:

есть прямоугольная сетка, на ней некоторое множество модельных организмов (т. н. агентов). Внутри каждого агента нейронная сеть. И каждый агент может передвигаться из клетки в клетку, общаться с другими агентами, размножаться (попутно мутируя) и умирать. То бишь получается навроде генетического алгоритма (такие вещи ещё называют “искусственной жизнью”, хотя данная конкретная модель не сказать чтобы уж очень живая).
Rodegast
> AgentLabel.update()

update это метод QLabel, а вы его переопределили.
Обедающий философ
Переименовал оба update, ничего принципиально не изменилось.
dartNNN
Эх, давно я за питон не брался:) хорошо то как:)
Итак
Обедающий философ
А у меня разве нет объектов?
Я имел ввиду предметную область разложить по объектам, чтобы правильно и без хаков (извращения) организовать код.
Вот есть у вас объект - доска на которой все лежит, так делаем ее как главный виджет для отображения и добавления Агентов, так он может выглядеть так:
class MyWidget(QtGui.QWidget):
def __init__(self):
super(QtGui.QWidget, self).__init__()
button = QtGui.QPushButton("Push me!")
button.clicked.connect(self.button_click)
self.layout = QtGui.QGridLayout()
self.layout.addWidget(button, 0,0)
self.layout.setHorizontalSpacing(0) #убираем расстояния между ячейками
self.layout.setVerticalSpacing(0)
self.setLayout(self.layout)
self.lines = 1

def some_magic_func(self, label, newText, line):
self.layout.addWidget(label, line, 0)
label.setText(newText)

def button_click(self):
self.lines += 1
label = Magic(self.layout)
self.some_magic_func(label, "Initial text", self.lines)
Также есть у вас объекты Агенты (фигня, лежащая на доске), которые (как я понял) сами решают куда перемещаться (что то там было про нейронную сеть?), вот пусть сами и решают (для наглядности по клику):
alph = list(map(chr, range(97, 123))) # делаем алфавит

class Magic(QtGui.QLabel):
def __init__(self, layout): # принимаем layout, по которому будем бегать
super(QtGui.QLabel, self).__init__()
self.layout = layout

def mousePressEvent(self, event): #переопределенный метод, вызывается при клике на лабел
index = self.layout.indexOf(self)
row, column, row_span, column_span = self.layout.getItemPosition(index)
self.init_mooooving(row, column + 1) # пляшем в право

def init_mooooving(self, row, column):
self.layout.removeWidget(self) # вот тебе и динамическое добавление/удаление - так и бежим
self.layout.addWidget(self, row, column)
Ну и в конце концов всю отрисовку (внешний вид доски) компактно складываем в один метод главного класса MyWidget, например так:
    def paintEvent(self, event):
painter = QtGui.QPainter()
painter.begin(self)
for column in range(self.layout.columnCount()):
self.layout.setColumnMinimumWidth(column, 100) # чтобы ячейки не сжимались до нуля.
for row in range(self.layout.rowCount()):
rect = self.layout.cellRect(row, column)
painter.drawRect(rect)
painter.end()
Не знаю точно всех мелочей, но по крайней мере то, что было описано работает. Без лишних извратов со скрытием/отображением.
Если что не понятно, спрашивай:)
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB