i want to display a message in pop-up window in python ...so i wrote this code...please check
import sys
from PyQt4.Qt import *
class MyPopup(QWidget):
def __init__(self):
print "6"
QWidget.__init__(self)
class MainWindow(QMainWindow):
def __init__(self, *args):
print "4"
QMainWindow.__init__(self, *args)
self.cw = QWidget(self)
self.setCentralWidget(self.cw)
self.btn1 = QPushButton("Start Chat", self.cw)
self.btn1.setGeometry(QRect(50, 30, 100, 30))
self.connect(self.btn1, SIGNAL("clicked()"), self.doit)
self.w = None
def doit(self):
print "5"
print "Opening a new popup window..."
self.w = MyPopup()
self.w.setGeometry(QRect(0, 0, 400, 200))
self.w.show()
class App(QApplication):
def __init__(self, *args):
print "3"
QApplication.__init__(self, *args)
self.main = MainWindow()
#self.connect(self, SIGNAL("lastWindowClosed()"), self.byebye )
self.main.show()
#def byebye( self ):
#self.exit(0)
for i in range(1, 5):
if __name__ == "__main__":
print "1"
global app
app = App(sys.argv)
app.exec_()
#main(sys.argv)
else:
print "over"
Here first loop its working but from second loop i m getting segmentation fault...guys please help me..
There is supposed to be just one QApplication object in an application. I guess your problem is that you attempt to create several in a loop.
If you want your user to close the main window four times before it actually closes, you can add an event handler:
class MainWindow(QMainWindow):
def __init__(self, *args):
...
self.counter = 1
def closeEvent(self, event):
print "closeEvent", self.counter
self.counter += 1
if self.counter < 5:
event.ignore()
else:
event.accept()
Related
I know this might be repeating the same question that someone else asked already, but I still don't understand what is happening actually. I have seen a lot of examples for multithreading in this forum and have compiled a dummy demo of what my actual application going to do. Here is the code:
import sys
from PySide2.QtCore import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
class Color(QWidget):
def __init__(self, color):
super(Color, self).__init__()
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.Window, QColor(color))
self.setPalette(palette)
class Inlet_Thread(QThread):
data = Signal(int)
tabs = Signal(int)
finish = Signal()
def __init__(self):
super().__init__()
self._stopped = False
self.init_timers()
print('new thread')
self.c = 0
self.d = 0
def init_timers(self):
self.timer1 = QTimer(self)
self.timer1.timeout.connect(self.routine)
self.timer2 = QTimer(self)
self.timer2.timeout.connect(self.routine2)
def starter(self):
self.timer1.start(1000)
self.timer2.start(2000)
def run(self):
while not self._stopped:
pass
self.timer1.stop()
self.timer2.stop()
print('stopped')
self.finish.emit()
def routine(self):
self.data.emit(self.c)
self.c += 1
def routine2(self):
self.tabs.emit(self.d)
self.d += 1
#Slot()
def stop(self):
self._stopped = True
class Inlet_Worker(QObject):
data = Signal(int)
tabs = Signal(int)
def __init__(self):
super().__init__()
self._stopped = False
self._registered = False
self.init_timers()
self.c = 0
self.d = 0
def init_timers(self):
self.timer1 = QTimer(self)
self.timer1.timeout.connect(self.routine)
self.timer2 = QTimer(self)
self.timer2.timeout.connect(self.routine2)
def starter(self):
self.timer1.start(1000)
self.timer2.start(2000)
def routine(self):
self.data.emit(self.c)
self.c += 1
def routine2(self):
self.tabs.emit(self.d)
self.d += 1
#Slot()
def stop(self):
self.timer1.stop()
self.timer2.stop()
print('stopped')
class Window(QWidget):
startSig = Signal()
stopSig = Signal()
def __init__(self):
super().__init__()
self.dlg = Dialog()
self.thread = None
pagelayout = QVBoxLayout(self)
button_layout = QHBoxLayout()
self.stacklayout = QStackedLayout()
pagelayout.addLayout(button_layout)
pagelayout.addLayout(self.stacklayout)
self.button = QPushButton('Start')
self.button2 = QPushButton('Stop')
self.button3 = QPushButton('Window')
button_layout.addWidget(self.button)
button_layout.addWidget(self.button2)
button_layout.addWidget(self.button3)
self.stacklayout.addWidget(Color("red"))
self.stacklayout.addWidget(Color("yellow"))
self.stacklayout.addWidget(Color("green"))
self.button.clicked.connect(self.startThr2)
self.button2.clicked.connect(self.stopThr)
self.button3.clicked.connect(self.showDlg)
#Slot(int)
def switch_tab(self, d):
idx = d % 3
print(idx)
self.stacklayout.setCurrentIndex(idx)
def showDlg(self):
if not self.dlg.isVisible():
self.dlg.show()
def startThr(self):
self.thread = QThread()
self.worker = Inlet_Worker()
self.worker.moveToThread(self.thread)
self.worker.data.connect(self.dlg.update)
self.worker.tabs.connect(self.switch_tab)
self.stopSig.connect(self.worker.stop)
self.thread.started.connect(self.worker.starter)
self.thread.start()
def startThr2(self):
if self.thread is None or not self.thread.isRunning():
self.thread = Inlet_Thread()
self.thread.started.connect(self.thread.starter)
self.thread.data.connect(self.dlg.update)
self.thread.tabs.connect(self.switch_tab)
self.thread.finish.connect(self.finished)
self.stopSig.connect(self.thread.stop)
self.thread.start()
def stopThr(self):
self.stopSig.emit()
def finished(self):
print('thread finished')
self.thread.quit()
self.thread.wait()
def closeEvent(self, event):
#self.stopThr()
pass
class Dialog(QWidget):
def __init__(self):
super().__init__()
self.text1 = QLabel("Label 1 : ")
self.text2 = QLabel("Text2")
layout = QHBoxLayout(self)
layout.addWidget(self.text1)
layout.addWidget(self.text2)
self.setGeometry(400, 100, 100, 50)
#Slot(int)
def update(self, sig):
self.text2.setText(str(sig))
def closeEvent(self, event):
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Window()
window.setGeometry(750, 80, 300, 80)
window.show()
sys.exit(app.exec_())
While the threading is performing fine, it returns an error:
QObject::killTimer: Timers cannot be stopped from another thread
And if I use the Qobject and move it to a thread, an additional error appears
QObject::~QObject: Timers cannot be stopped from another thread
Can someone explain what is causing the error?
EDIT:
I changed the code to be more complex and show where each data will go. The reason I'm using Qtimer in a thread is that there are multiple signals to emit and the frequency and shape of each data is different. Since this code is only a simplification of my actual application, there might be some different parts. And if there are alternatives, I'm open to suggestions.
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'm making a program to specify a specific area using pyqt5.
If I click on the capture button, I will hide the MainWindow and display a screen to specify the area. I want to clear the screen and return to the mainwindow by pressing the esc key. But MainWindow does not show again. How should I work it?
form_class = uic.loadUiType("prototype.ui")[0]
class MainWindow(QtWidgets.QMainWindow, form_class) :
def __init__(self):
super().__init__()
self.setupUi(self)
self.Capture_Button.clicked.connect(self.Capture_Btn_clicked)
self.CaptureWindow = CaptureWidget()
self.CaptureWindow.hide()
def Capture_Btn_clicked(self) :
self.hide()
self.CaptureWindow.close()
self.CaptureWindow.__init__()
self.CaptureWindow.show()
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
def enterEvent(self, QEvent):
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.setWindowOpacity(1)
This is the class that specifies the area (some of the code is omitted).
class CaptureWidget(QtWidgets.QDialog):
def __init__(self):
super().__init__()
root = tk.Tk()
self.setupUi(self)
def setupUi(self) :
self.screen_width = root.winfo_screenwidth()
self.screen_height = root.winfo_screenheight()
self.setGeometry(0, 0, self.screen_width, self.screen_height)
self.setWindowTitle(' ')
self.begin = QtCore.QPoint()
self.end = QtCore.QPoint()
self.setWindowOpacity(0.3)
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
self.setWindowFlags(QtCore.Qt.FramelessWindowHint|QtCore.Qt.WindowStaysOnTopHint)
print('Capture the screen...')
self.is_set_region = False
self.is_mouse_click = False
self.show()
def keyPressEvent(self, event):
key = event.key()
if key == Qt.Key_Escape:
print('esc')
self.close()
elif key == Qt.Key_F1:
self.close()
self.__init__()
First of all, instead of overwriting the keyPressEvent method, it is easier to use QShortcut. On the other hand for this case it is better to create a signal that indicates when the escape key is pressed connecting it to the show method.
from PyQt5 import QtCore, QtGui, QtWidgets, uic
class CaptureWidget(QtWidgets.QDialog):
escape_pressed = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
self.setupUi()
def setupUi(self):
self.setWindowOpacity(0.3)
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowStaysOnTopHint)
shorcut_scaped = QtWidgets.QShortcut(QtCore.Qt.Key_Escape, self)
shorcut_scaped.activated.connect(self.escape_pressed)
shorcut_scaped.activated.connect(self.close)
shorcut = QtWidgets.QShortcut(QtCore.Qt.Key_F1, self)
shorcut.activated.connect(self.close)
form_class, _ = uic.loadUiType("prototype.ui")
class MainWindow(QtWidgets.QMainWindow, form_class):
def __init__(self):
super().__init__()
self.setupUi(self)
self.Capture_Button.clicked.connect(self.Capture_Btn_clicked)
self.CaptureWindow = CaptureWidget()
self.CaptureWindow.escape_pressed.connect(self.show)
#QtCore.pyqtSlot()
def Capture_Btn_clicked(self):
self.hide()
self.CaptureWindow.showFullScreen()
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
def enterEvent(self, QEvent):
QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.setWindowOpacity(1)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
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_())
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_())