Найти - Пользователи
Полная версия: Торможения таймера при зарисовки цветом
Начало » GUI » Торможения таймера при зарисовки цветом
1 2 3 4
zeze
Прямоугольная область с торможениями закрашивается красным цветом. Но вот один раз я абсолютно также сделал и прямоугольная область быстро начала зарисовыватся красным цветом.
Как будто это сбой самого Pathon-а. Решил привести полный код. Может кто увидит, где может быть ошибка и отпишется.
Мой код:

# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui, uic
import math
import os
import struct
phi = 0.0
timer = QtCore.QTimer()
im = QtGui.QImage(720, 492, QtGui.QImage.Format_ARGB32)
class ld(QtGui.QDialog):
    def __init__(self, parent=None):
        super(ld, self).__init__(parent)
        self.ui = uic.loadUi("ld.ui", self)
        self.connect(timer, QtCore.SIGNAL("timeout()"), self.MyTimer)
        timer.start((0.05 * 1000) / 60)
    def paintEvent(self, QPaintEvent):
        if self.ui.radioButton.isChecked():
            painterRect = QtGui.QPainter(self)
            painterRect.setBrush(QtGui.QColor('black'))
            painterRect.drawRect(50, 50, 720, 492)
            self.MyDraw()
        self.update()
    def MyRadianToGradus(self, phiedit):
        gradus = phiedit * 360 / (2 * math.pi)
        return gradus
    def MyGradusToRadian(self, phiedit):
        radian = phiedit * 2 * math.pi / (360)
        return radian
    def MyTimer(self):
        global phi
        global im
        if self.ui.checkBox.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())
        self.update()
        if int(self.MyRadianToGradus(phi) + 0.5) * 720 / 360 < 720:
            phi += self.MyGradusToRadian(6.0)
        else:
            phi = self.MyGradusToRadian(6.0)
    def MyDraw(self):
        global im
        global phi
        Tochka = QtGui.QPainter()
        Tochka.begin(self)
        Tochka.translate(50, 50)
        Tochka.drawImage(0, 0, im, 0, 0, int((2 * self.MyRadianToGradus(phi)) + 0.5), 492)
        Tochka.end()
if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = ld()
    window.show()
    sys.exit(app.exec_())

А почему он в Python иногда проскакивает с быстрой скоростью? То есть раз 5 работало медленно, потом заработало быстро, а потом 15 раз медленно.
Принцип такой, я копировал папку с проектом и удалял не нужный код, до того кода который я выложил.

Я сделал так

timer.start(5000)

Проверял на секундомере на смартфоне. В итоге первые несколько раз по 3 секунды, а потом идёт интервал по 5 секунд, даже немного поменьше (4,7 или 4,8 секунды).

Я делал так

timer.start(15)

Картинка через каждые 0,5 секунды обновляется.
1. Что же с этим таймером?
2. Может я таймер не правильно описываю в коде, хотя Python ни какие ошибки не выдаёт?
Loki
Как по мне, то такая программа, сама по себе, на момент создания концепции, уже была ошибочна.
Во-первых: ты вызываешь перерисовку всего окна по таймеру и ждешь следующей перерисовки от таймера, это не верно (конечно, это мое, субьективное, мнение).
Во-вторых: для таких целей обычно используют модель-представление (опять только по моему очень небольшому опыту)
В-третих: если ты все же решил не пользоватся модель-представлением, то тебе нужно вынести таймер в отдельный поток и из этого потока посылать сигнал (не перерисовывать напрямую из паралельного потока, а только сигнал) и перерисовывать окно по сигналу.

Предположим, что ты хотел, чтобы окно твоей программы “подвисало” и с опозданием реагировало на события мыши. Тогда ты скорее всего стартуешь таймер не из того метода, почему именно с __init__?, ведь на момент инициализации экземпляра класса, таймер у тебя уже запущен и идет набор значения phi, так как в в методе MyTimer ты в не зависимости от того активен self.checkBox или нет, проверяешь phi на условие и в зависимости от результата меняешь его. Т.е. переменная характеризующая степень законченности процесса наберает значение без самого процесса.
zeze
Loki
в методе MyTimer ты в не зависимости от того активен self.checkBox или нет, проверяешь phi на условие и в зависимости от результата меняешь его. Т.е. переменная характеризующая степень законченности процесса наберает значение без самого процесса.

Я понял Вас и переделал код, так:

def MyTimer(self):
        global phi
        global im1
        if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())
            self.update()
            if int(self.MyRadianToGradus(phi)+0.5)*720/360 < 720:
                phi += self.MyGradusToRadian(6.0)
            else:
                phi = self.MyGradusToRadian(6.0)

Loki
Предположим, что ты хотел, чтобы окно твоей программы “подвисало” и с опозданием реагировало на события мыши.

Я не хотел подвисаний.

Loki
Тогда ты скорее всего стартуешь таймер не из того метода, почему именно с __init__?, ведь на момент инициализации экземпляра класса, таймер у тебя уже запущен и идет набор значения phi

Я хотел объявить запуск таймера, как я это делал в Qt из конструктора, но из Вашего вопроса я понял, что __init__ не конструктор, а где же тогда надо было запускать таймер?
Loki
Я хотел объявить запуск таймера, как я это делал в Qt из конструктора, но из Вашего вопроса я понял, что __init__ не конструктор, а где же тогда надо было запускать таймер?
Запускать таймер нужно там где это логично и действительно нужно, например при нажатии на кнопку у тебя что-то должно выполнется через определенный момент, ну так и привязывай запуск таймера по событию кнопки…
Метод __init__ действительно конструктор и он запускается в момент создания экземпляра класса, и если он является конструктором класса, то это не значит, что именно в нем нужно стартовать таймер, ведь это бессмысленно - тебе так не кажется?…
Я не хотел подвисаний.
Если не хочешь чтобы программа висела не делай update() по таймеру.
zeze
Loki
Если не хочешь чтобы программа висела не делай update() по таймеру.

Удалил из таймера update(). Таймер начал запускать и останавливать по нажатию кнопки. А всёравно медленно закрашивается. Почему так происходит?
Мой код:
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui, uic
import math
import os
import struct
phi = 0.0
im1 = QtGui.QImage(720, 492, QtGui.QImage.Format_ARGB32)
class ld(QtGui.QDialog):
    def __init__(self, parent=None):
        super(ld, self).__init__(parent)
        self.ui = uic.loadUi("ld.ui", self)
        self.connect(self.ui.radioButton, QtCore.SIGNAL("clicked()"), self.MyClickRect)
        self.connect(self.ui.pushButton_3, QtCore.SIGNAL("clicked()"), self.BlockTimer)
        self.timer = QtCore.QTimer()
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.MyTimer)
        self.ui.pushButton.setText(u"Запустить")
    def paintEvent(self, QPaintEvent):
        if self.ui.radioButton.isChecked():     # Выбор прямоугольных координат
            self.MyDraw()
            self.update()
    def MyClickRect(self):
        self.update()
    def MyRadianToGradus(self, phiedit):
        gradus = phiedit * 360/(2*math.pi)
        return gradus
    def MyGradusToRadian(self, phiedit):
        radian = phiedit * 2*math.pi / (360)
        return radian
    def MyTimer(self):
        global phi
        global im1
        if self.ui.checkBox.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())
            if int(self.MyRadianToGradus(phi)+0.5)*720/360 < 720:
                phi += self.MyGradusToRadian(6.0)
            else:
                phi = self.MyGradusToRadian(6.0)
    def MyDraw(self):
        global im1
        global phi
        Tochka = QtGui.QPainter()
        Tochka.begin(self)
        Tochka.translate(50, 50)
        Tochka.drawImage(0, 0, im, 0, 0, int((2*self.MyRadianToGradus(phi))+0.5), 492)
        Tochka.end()
    def BlockTimer(self):
        # Выбор "Запустить"
        if self.ui.pushButton.text() == u"Запустить":
            self.timer.start((0.005 * 1000) / 60)
            self.ui.pushButton.setText(u"Остановить")
        else:
            self.timer.stop()
            self.ui.pushButton.setText(u"Запустить")
if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = ld()
    window.show()
    sys.exit(app.exec_())
Loki
Попробую вечером сделать тебе пример с многопоточным приложением…
zeze
Loki
Попробую вечером сделать тебе пример с многопоточным приложением…

Хорошо, буду ждать.
Не ужели для такой простой задачи в Python без потоков не обойтись?
agalen
Это будет тормозить всегда:
    for j in range(0, 720, 1):
for i in range(491, -1, -1):
im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())
zeze
agalen
Это будет тормозить всегда:

for j in range(0, 720, 1):
        for i in range(491, -1, -1):
            im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

Объясните пожалуйста эти торможения, так как в Qt их нету?

И какже быть?
Дело в том, что мне нужно каждый раз, чтобы по таймеру менялись и рисовались разные картинки. А данная зада лишь упрощённый пример для понимания.
Loki
Окно немного “подтармаживает” в момент установки нового рисунка, сделал потокоНЕбезопасным способом, только в качестве примера:
# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui
import sys, math
class MyThread(QtCore.QThread):
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)
        self.running = False        
        self.phi=0.0
    def run(self):       
        self.running = True
        while self.running:
            self.emit(QtCore.SIGNAL("mysignal(QString)"),
                      "%s" % self.phi)
            if int(self.MyRadianToGradus(self.phi)+0.5)*280/360 < 280:                
                self.phi += self.MyGradusToRadian(20.0)
            else:
                self.phi = self.MyGradusToRadian(0.0)            
            self.sleep(1)
    def MyRadianToGradus(self, phiedit):
        gradus = phiedit * 360/(2*math.pi)
        return gradus
    def MyGradusToRadian(self, phiedit):
        radian = phiedit * 2*math.pi / (360)
        return radian                
class MyLabel(QtGui.QLabel):    
    def __init__(self, title=None, parent=None):
        super(MyLabel, self).__init__(title, parent)
        self.setFrameShape(QtGui.QFrame.Box)
        self.setMinimumSize(280,50)        
        self.setText("<font color='red'>Закрашивание полосы</font>")
        self.phi = 0.0    
    def MyDraw(self, phi):        
        phi = 270/6.2*phi
        im = QtGui.QImage(270, 40, QtGui.QImage.Format_ARGB32)
        for j in range(0, 270, 1):
            for i in range(39, -1, -1):                
                if j<phi:
                    im.setPixel(j, i, QtGui.QColor('gray').rgba())
                else:
                    im.setPixel(j, i, QtGui.QColor('red').rgba())
        self.setPixmap(QtGui.QPixmap(im))
    
class MyWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.label = MyLabel()
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.btnStart = QtGui.QPushButton("Запустить зарисовку")
        self.btnStop = QtGui.QPushButton("Остановить зарисовку")
        self.btnStop.setEnabled(False)
        self.vbox = QtGui.QVBoxLayout()
        self.vbox.addWidget(self.label)
        self.vbox.addWidget(self.btnStart)
        self.vbox.addWidget(self.btnStop)
        self.setLayout(self.vbox)
        self.mythread = MyThread()
        self.connect(self.btnStart, QtCore.SIGNAL("clicked()"),
                     self.on_start)
        self.connect(self.btnStop, QtCore.SIGNAL("clicked()"),
                     self.on_stop)
        self.connect(self.mythread, QtCore.SIGNAL("mysignal(QString)"),
                     self.on_change, QtCore.Qt.QueuedConnection)
    def on_start(self):
        if not self.mythread.isRunning():
            self.mythread.start()
            self.btnStart.setEnabled(False)
            self.btnStop.setEnabled(True)
    def on_stop(self):
        self.mythread.running = False
        self.btnStart.setEnabled(True)
        self.btnStop.setEnabled(False)
    def on_change(self, phi):
        self.label.MyDraw(float(phi))
    def closeEvent(self, event):      
        self.hide()                    
        self.mythread.running = False  
        self.mythread.wait(5000)       
        event.accept()                 
if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    window = MyWindow()
    window.setWindowTitle("Запуск и остановка закрашивания")
    window.resize(300, 100)
    window.show()
    sys.exit(app.exec_())
Попробуй использовать модель представление.
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