I'm developing some programe in python.
Now i can open a second window but now i will go back to my first window.
My problem is when i push the close button my first and second window close.
And i will that only my second window closed.
My code:
import sys
from PyQt4 import QtCore, QtGui
from forms.runtime_form import Ui_runtime_form
import datetime
import time
"""
The main class
First window
"""
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
self.run_mode = 0
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_runtime_form()
self.ui.setupUi(self)
self.main_thread = main_thread(self)
self.main_thread.start()
self.main_thread.update_date_time.connect(self.update_date_time)
if self.run_mode == 0:
Uit = QtGui.QPushButton('Uit', self)
Uit.move(20,650)
Uit.clicked.connect(QtCore.QCoreApplication.instance().quit)
#button to open second window
bla = QtGui.QPushButton('bla', self)
bla.move(150,650)
bla.clicked.connect(self.child)
#open second window
def child(self):
test = Example(self)
test.showFullScreen()
def update_date_time(self):
#some other code
#Second window
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
Uit = QtGui.QPushButton('Uit', self)
Uit.clicked.connect(self.sluit)
Uit.move(150,50)
self.setGeometry(300, 300, 500, 150)
self.setWindowTitle('Modbus Domotica - Touchscreen')
self.show()
#Close second window
def sluit(self):
sys.exit(0)
class main_thread(QtCore.QThread):
update_date_time = QtCore.pyqtSignal()
def __init__(self, layout):
QtCore.QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
while True:
self.update_date_time.emit()
time.sleep(10)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
QtGui.QApplication.setPalette(QtGui.QApplication.style().standardPalette())
myapp = StartQT4()
myapp.showFullScreen()
sys.exit(app.exec_())
Of course both windows close, you are exiting Python!
#Close second window
def sluit(self):
sys.exit(0)
Instead, try -
def sluit(self):
self.close()
Related
I need to create a custom signal on Qmdisubwindow close. In other word, when I closed any subwindow, a signal is emitted with the name of that window being closed. Below is my trail, but seems not right. Error occurs as:
a subwindow already created without calling
add subwindow option is not working
closable action is not working
Hope you can show me how to fix it.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MyMdi(QMdiSubWindow):
sigClosed = pyqtSignal(str)
def __init__(self, parent=None):
super(MyMdi, self).__init__(parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
name = name
self.sigClosed.emit('{} is close'.format(name))
QMdiSubWindow.closeEvent(self, event)
class MainWindow(QMainWindow):
count = 0
def __init__(self, parent = None):
super(MainWindow, self).__init__(parent)
self.mdi = MyMdi()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
file.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI demo")
# my signal
self.mdi.sigClosed.connect(self.windowclosed)
#pyqtSlot(str)
def windowclosed(self, text):
print(text)
def windowaction(self, q):
if q.text() == "New":
MainWindow.count = MainWindow.count+1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow"+str(MainWindow.count))
self.mdi.addSubWindow(sub)
sub.show()
def main():
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You have an initial error: a QMdiSubWindow must be inside a QMdiArea but there is none in your code.
On the other hand, the idea of subclassing is good but you have several drawbacks:
You are not using it initially since there is no QMdiArea, if you execute the QAction then your application will be closed because a QMdiSubWindow does not have any method called addSubWindow.
The QMdiSubWindow does not have an attribute called name, you must use windowTitle.
class MdiSubWindow(QMdiSubWindow):
sigClosed = pyqtSignal(str)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
self.sigClosed.emit(self.windowTitle())
QMdiSubWindow.closeEvent(self, event)
class MainWindow(QMainWindow):
count = 0
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("File")
file.addAction("New")
file.triggered[QAction].connect(self.windowaction)
self.setWindowTitle("MDI demo")
#pyqtSlot(str)
def windowclosed(self, text):
print(text)
def windowaction(self, q):
if q.text() == "New":
MainWindow.count = MainWindow.count + 1
sub = MdiSubWindow()
sub.setWidget(QTextEdit())
sub.setAttribute(Qt.WA_DeleteOnClose)
sub.setWindowTitle("subwindow" + str(MainWindow.count))
sub.sigClosed.connect(self.windowclosed)
self.mdi.addSubWindow(sub)
sub.show()
I would like to ask how to make the text in QTextEdit scoll, to achieve an animational effect. The animational effect should be something like what in the video shows: https://www.youtube.com/watch?v=MyeuGdXv4XM
With PyQt I want to get this effect:
The text should be scolled automatically at a speed of 2 lines/second downwards, till it reaches the end and stops.
In my code below, when the button is clicked, the text is shown in QTextEdit-Widget. The text is very long, so that the scroll bar is shown.
My Problem:
I dont know how to make the animation effect. Thus I would like to ask your help to correct my code.
# -*- coding: utf-8 -*-
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
import time
list_longText = [" long text 1 - auto scrolling " * 1000, " long text 2 - auto scrolling " * 2000]
class Worker(QObject):
finished = pyqtSignal()
strTxt = pyqtSignal(str)
def __init__(self, parent=None):
super(Worker, self).__init__(parent)
#pyqtSlot()
def onJob(self):
for i in range(2):
self.strTxt.emit(list_longText[i])
time.sleep(2)
class MyApp(QWidget):
def __init__(self):
super(MyApp, self).__init__()
self.setFixedSize(600, 400)
self.setObjectName("window")
self.initUI()
def initUI(self):
self.txt = QTextEdit("", self)
self.btn = QPushButton("Button", self)
self.btn.clicked.connect(self.start)
self.layout = QHBoxLayout(self)
self.layout.addWidget(self.txt)
self.layout.addWidget(self.btn)
self.setLayout(self.layout)
self.show()
def start(self):
self.thread = QThread()
self.obj = Worker()
self.obj.strTxt.connect(self.showText)
self.obj.moveToThread(self.thread)
self.obj.finished.connect(self.thread.quit)
self.thread.started.connect(self.obj.onJob)
self.thread.start()
def showText(self, str):
self.txt.setText("{}".format(str))
self.autoScroll()
def autoScroll(self):
vsb = self.txt.verticalScrollBar()
if vsb.value() <= vsb.maximum():
vsb.setValue(vsb.value() + 2)
time.sleep(1)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyApp()
sys.exit(app.exec_())
Thanks very much for the help!
The task you want is not heavy, it is periodic so using a thread is inappropriate, for this task we can use QVariantAnimation.
The other part is to create a method that moves to a certain line of text for it we use QTextCursor next to findBlockByLineNumber() of QTextDocument.
And for the last one we must start moving to the last initial visible for it we use the cursorForPosition() method through the size of the viewport().
longText = "\n".join(["{}: long text - auto scrolling ".format(i) for i in range(100)])
class AnimationTextEdit(QTextEdit):
def __init__(self, *args, **kwargs):
QTextEdit.__init__(self, *args, **kwargs)
self.animation = QVariantAnimation(self)
self.animation.valueChanged.connect(self.move)
#pyqtSlot()
def startAnimation(self):
self.animation.stop()
lines_per_second = 2
self.moveToLine(0)
p = QPoint(self.viewport().width() - 1, self.viewport().height() - 1)
cursor = self.cursorForPosition(p)
self.animation.setStartValue(cursor.blockNumber())
self.animation.setEndValue(self.document().blockCount()-1)
self.animation.setDuration(self.animation.endValue()*1000/lines_per_second)
self.animation.start()
#pyqtSlot(QVariant)
def move(self, i):
cursor = QTextCursor(self.document().findBlockByLineNumber(i))
self.setTextCursor(cursor)
class MyApp(QWidget):
def __init__(self):
super(MyApp, self).__init__()
self.setFixedSize(600, 400)
self.txt = AnimationTextEdit(self)
self.btn = QPushButton("Start", self)
self.layout = QHBoxLayout(self)
self.layout.addWidget(self.txt)
self.layout.addWidget(self.btn)
self.txt.append(longText)
self.txt.move(0)
self.btn.clicked.connect(self.txt.startAnimation)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
Update:
if you want a continuous movement you must use verticalScrollBar():
longText = "\n".join(["{}: long text - auto scrolling ".format(i) for i in range(100)])
class AnimationTextEdit(QTextEdit):
def __init__(self, *args, **kwargs):
QTextEdit.__init__(self, *args, **kwargs)
self.animation = QVariantAnimation(self)
self.animation.valueChanged.connect(self.moveToLine)
#pyqtSlot()
def startAnimation(self):
self.animation.stop()
self.animation.setStartValue(0)
self.animation.setEndValue(self.verticalScrollBar().maximum())
self.animation.setDuration(self.animation.endValue()*4)
self.animation.start()
#pyqtSlot(QVariant)
def moveToLine(self, i):
self.verticalScrollBar().setValue(i)
class MyApp(QWidget):
def __init__(self):
super(MyApp, self).__init__()
self.setFixedSize(600, 400)
self.txt = AnimationTextEdit(self)
self.btn = QPushButton("Start", self)
self.layout = QHBoxLayout(self)
self.layout.addWidget(self.txt)
self.layout.addWidget(self.btn)
self.txt.append(longText)
self.txt.moveToLine(0)
self.btn.clicked.connect(self.txt.startAnimation)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MyApp()
window.show()
sys.exit(app.exec_())
I'm new to PyQT and QThread. My PyQT program has a button which trigger a continuous writing/reading of the serial port every second.
Problem: When the button is clicked and the looping starts, the GUI freezes up. Am I using QThread wrongly?
import sys
from PyQt4.QtGui import *
from PyQt4 import QtCore
import serial
import time
from TemperatureReader import TemperatureReader # my module to talk to serial hardware
class Screen(QMainWindow):
def __init__(self):
super(Screen, self).__init__()
self.initTemperatureReader()
self.initUI()
def initTemperatureReader(self):
ser = serial.Serial(port='COM9', baudrate=115200, timeout=5)
self.temperatureReader = TemperatureReader(ser)
def initUI(self):
startReadingTCsBtn = QPushButton('Start Reading')
startReadingTCsBtn.clicked.connect(self.startReadingTCsThread)
startReadingTCsBtn.show()
directControlBoxLayout = QVBoxLayout()
directControlBoxLayout.addWidget(startReadingTCsBtn)
self.mainFrame = QWidget()
mainLayout = QVBoxLayout()
mainLayout.addWidget(directControlGroupBox)
self.mainFrame.setLayout(mainLayout)
self.setCentralWidget(self.mainFrame)
self.setGeometry(300,300,400,150)
self.show()
def startReadingTCsThread(self):
self.tcReaderThread = TCReaderThread(self.temperatureReader)
self.tcReaderThread.temperatures.connect(self.onTemperatureDataReady)
self.tcReaderThread.start()
def onTemperatureDataReady(self, data):
print data
class TCReaderThread(QtCore.QThread):
temperatures = QtCore.pyqtSignal(object)
def __init__(self, temperatureReader):
QtCore.QThread.__init__(self)
self.temperatureReader = temperatureReader
def run(self):
while True:
resultString = self.temperatureReader.getTemperature() # returns a strng
self.temperatures.emit(resultString)
time.sleep(1)
def main():
app = QApplication(sys.argv)
screen = Screen()
app.exec_()
if __name__ == '__main__':
main()
I have the problem. I made the thread and from there I want to open the new window. But it does not work.
import sys
from grab import Grab
from PyQt4 import QtGui, QtCore
class Requests(QtCore.QThread):
def __init__(self, parent=None):
QtCore.QThread.__init__(self, parent)
def run(self):
# here some comands
self.emit(QtCore.SIGNAL("mysignal(QString)"), 'open')
class window(QtGui.QWidget):
def __init__(self, parent = None):
QtGui.QWidget.__init__(self, parent)
self.setGeometry(100, 100, 500, 200)
self.setWindowTitle('Window')
self.label = QtGui.QLabel(u'Hello')
self.Layout = QtGui.QVBoxLayout()
self.Layout.addWidget(self.label)
self.setLayout(self.Layout)
self.c = Requests()
self.c.start()
self.connect(self.c, QtCore.SIGNAL("mysignal(QString)"), self.open_window, QtCore.Qt.QueuedConnection)
def open_window(self):
print 'open modal window'
modal_w = popup_window()
modal_w.show()
app = QtGui.QApplication(sys.argv)
main = window()
main.show()
sys.exit(app.exec_())
It is not show new window. Where is the error?
You need to connect the signal before the thread starts, and hence before the signal is emitted. If you want to show a dialog when the worker thread completes, just use the finished signal:
class Requests(QtCore.QThread):
def run(self):
# do some work...
print 'work finished'
...
self.c = Requests()
self.c.finished.connect(self.open_window)
self.c.start()
You also need to keep a reference to the dialog when opening it in the slot:
def open_window(self):
print 'open modal window'
self.modal_w = popup_window()
self.modal_w.show()
There will be as many Progress Bars created as there are entities in myList.
Clicking Ok button starts as many sub-processes as there are entities in myList.
Problem:
1. It seems there are way more sub-processes started than entities in myList.
2. Unable to update ProgressBar with a line(that's why it is commented):
pb.update_bar( self.pBars[each]['value'] )
import sys, os
from PyQt4 import QtCore, QtGui
import threading
import time
class PbWidget(QtGui.QProgressBar):
def __init__(self, parent=None, total=20):
super(PbWidget, self).__init__()
self.setMinimum(1)
self.setMaximum(total)
self._active = False
def update_bar(self, to_add_number):
while True:
time.sleep(0.01)
value = self.value() + to_add_number
self.setValue(value)
QtGui.qApp.processEvents()
if (not self._active or value >= self.maximum()):
break
self._active = False
def closeEvent(self, event):
self._active = False
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.myList = ['One','Two','Three','Four','Five','Six','Seven']
self.main_layout = QtGui.QVBoxLayout()
self.pBars={}
for each in self.myList:
pb=PbWidget(total=101)
self.main_layout.addWidget(pb)
self.pBars[each]={'pb':pb, 'name':each, 'value': 0}
ok_button = QtGui.QPushButton("Distribute")
ok_button.clicked.connect(self.OK)
self.main_layout.addWidget(ok_button)
central_widget = QtGui.QWidget()
central_widget.setLayout(self.main_layout)
self.setCentralWidget(central_widget)
def internalFunc(self, myEvent, each):
pb = self.pBars[each]['pb']
state=True
while state:
if self.pBars[each]['value']>=100: state=False
for i in range(12):
self.pBars[each]['value']+=10
print '\n\t ...Working on', each, self.pBars[each]['value'], '\n'
# pb.update_bar( self.pBars[each]['value'] )
time.sleep(0.5)
print "\n\t ProgressBar", each, 'has reached 100%. Its value =', self.pBars[each]['value'], '\n'
def OK(self):
for each in self.pBars:
self.myEvent=threading.Event()
self.c_thread=threading.Thread(target=self.internalFunc, args=(self.myEvent, each,))
self.c_thread.start()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.resize(480, 320)
window.show()
sys.exit(app.exec_())