Python Forum
[PyQt] timer makes my qmessagebox crash
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyQt] timer makes my qmessagebox crash
#1
Hi
I made a timer program. Where you write the time in some text boxes and when the clock hits that time
it should show a messagebox. But my problem is the messagebox crashes. i have no ide why.
could anyone help me?

import sys
from datetime import datetime
from threading import Timer
 
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QPushButton, QLineEdit, QMessageBox
from PySide2.QtCore import QFile, QObject
 
class Form(QObject):
 
    def __init__(self, ui_file, parent=None):
        super(Form, self).__init__(parent)
        ui_file = QFile(ui_file)
        ui_file.open(QFile.ReadOnly)
 
        loader = QUiLoader()
        self.window = loader.load(ui_file)
        ui_file.close()
 
        self.timmar = self.window.findChild(QLineEdit, 'timmar')
        self.minuter = self.window.findChild(QLineEdit, 'minuter')
        self.sekunder = self.window.findChild(QLineEdit, 'sekunder')
        self.textmsg = self.window.findChild(QLineEdit, 'textmsg')
 
        btn = self.window.findChild(QPushButton, 'pushButton')
        btn.clicked.connect(self.ok_handler)
        self.window.show()

        
    def ok_handler(self):

        timmarValue = int(self.timmar.text())
        minuterValue = int(self.minuter.text())
        sekunderValue = int(self.sekunder.text())
        
        x=datetime.today()
        y=x.replace(day=x.day+1, hour=timmarValue, minute=minuterValue, second=sekunderValue, microsecond=0)
        delta_t=y-x

        secs=delta_t.seconds+1

        t = Timer(secs, self.hello_world)
        t.daemon = True
        t.start()
        
    def hello_world(self):
        textmsg = self.textmsg.text()   
        print (textmsg)
        
        msgBox = QMessageBox()
        msgBox.setIcon(QMessageBox.Information)
        msgBox.setText("Message box pop up window")
        msgBox.setWindowTitle("QMessageBox Example")
        msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

        returnValue = msgBox.exec()
        if returnValue == QMessageBox.Ok:
           print('OK clicked')
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = Form('time2gui.ui')
    sys.exit(app.exec_())
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Form</class>
 <widget class="QWidget" name="Form">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>272</width>
    <height>165</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="QWidget" name="layoutWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>251</width>
     <height>141</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout_8">
    <item>
     <layout class="QVBoxLayout" name="verticalLayout_7">
      <item>
       <layout class="QGridLayout" name="gridLayout">
        <item row="0" column="0">
         <layout class="QVBoxLayout" name="verticalLayout">
          <item>
           <widget class="QLabel" name="label_3">
            <property name="text">
             <string>H</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QLineEdit" name="timmar">
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
         </layout>
        </item>
        <item row="0" column="1">
         <layout class="QVBoxLayout" name="verticalLayout_2">
          <item>
           <widget class="QLabel" name="label_4">
            <property name="text">
             <string>:</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QLabel" name="label">
            <property name="text">
             <string>:</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
         </layout>
        </item>
        <item row="0" column="2">
         <layout class="QVBoxLayout" name="verticalLayout_3">
          <item>
           <widget class="QLabel" name="label_5">
            <property name="text">
             <string>M</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QLineEdit" name="minuter">
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
         </layout>
        </item>
        <item row="0" column="3">
         <layout class="QVBoxLayout" name="verticalLayout_4">
          <item>
           <widget class="QLabel" name="label_7">
            <property name="text">
             <string>:</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QLabel" name="label_2">
            <property name="text">
             <string>:</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
         </layout>
        </item>
        <item row="0" column="4">
         <layout class="QVBoxLayout" name="verticalLayout_5">
          <item>
           <widget class="QLabel" name="label_6">
            <property name="text">
             <string>S</string>
            </property>
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
          <item>
           <widget class="QLineEdit" name="sekunder">
            <property name="alignment">
             <set>Qt::AlignCenter</set>
            </property>
           </widget>
          </item>
         </layout>
        </item>
       </layout>
      </item>
      <item>
       <layout class="QVBoxLayout" name="verticalLayout_6">
        <item>
         <widget class="QLabel" name="label_8">
          <property name="text">
           <string>Text Meddelande</string>
          </property>
          <property name="alignment">
           <set>Qt::AlignCenter</set>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QLineEdit" name="textmsg"/>
        </item>
       </layout>
      </item>
     </layout>
    </item>
    <item>
     <widget class="QPushButton" name="pushButton">
      <property name="text">
       <string>Start</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>
Reply
#2
time2gui.ui is missing.
Reply
#3
(Feb-10-2020, 08:20 PM)Axel_Erfurt Wrote: time2gui.ui is missing.

it there now
Reply
#4
I can test it only with PyQt5 and there it works.

(I must changed some lines)

import sys
from datetime import datetime
from threading import Timer
  
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QPushButton, QLineEdit, QMessageBox
from PyQt5.QtCore import QFile, QObject
  
class Form(QObject):
  
    def __init__(self, ui_file, parent=None):
        super(Form, self).__init__(parent)
        ui_file = QFile(ui_file)
        ui_file.open(QFile.ReadOnly)
  
        #loader = QUiLoader()
        self.window = uic.loadUi(ui_file)
        ui_file.close()
  
        self.timmar = self.window.findChild(QLineEdit, 'timmar')
        self.minuter = self.window.findChild(QLineEdit, 'minuter')
        self.sekunder = self.window.findChild(QLineEdit, 'sekunder')
        self.textmsg = self.window.findChild(QLineEdit, 'textmsg')
        self.textmsg.setText("Hello")
  
        btn = self.window.findChild(QPushButton, 'pushButton')
        btn.clicked.connect(self.ok_handler)
        self.window.show()
 
         
    def ok_handler(self):
        print("started")
        x=datetime.today()
        self.timmar.setText(str(x.hour))
        self.minuter.setText(str(x.minute))
        self.sekunder.setText(str(x.second + 5))
        
        timmarValue = int(self.timmar.text())       
        minuterValue = int(self.minuter.text())
        sekunderValue = int(self.sekunder.text())
         
        y=x.replace(day=x.day+1, hour=timmarValue, minute=minuterValue, second=sekunderValue, microsecond=0)
        delta_t=y-x
 
        secs=delta_t.seconds+1
 
        t = Timer(secs, self.hello_world)
        t.daemon = True
        t.start()
         
    def hello_world(self):
        textmsg = self.textmsg.text()   
        print (textmsg)
         
        msgBox = QMessageBox(QMessageBox.Information, "QMessageBox Example", \
                                f"Message box pop up window\n{textmsg}", \
                                QMessageBox.Ok | QMessageBox.Cancel)
 
        returnValue = msgBox.exec()
        if returnValue == QMessageBox.Ok:
           print('OK clicked')
         
if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = Form('/tmp/time2gui.ui')
    sys.exit(app.exec_())
Reply
#5
(Feb-10-2020, 09:06 PM)Axel_Erfurt Wrote: I can test it only with PyQt5 and there it works.

(I must changed some lines)

import sys
from datetime import datetime
from threading import Timer
  
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QPushButton, QLineEdit, QMessageBox
from PyQt5.QtCore import QFile, QObject
  
class Form(QObject):
  
    def __init__(self, ui_file, parent=None):
        super(Form, self).__init__(parent)
        ui_file = QFile(ui_file)
        ui_file.open(QFile.ReadOnly)
  
        #loader = QUiLoader()
        self.window = uic.loadUi(ui_file)
        ui_file.close()
  
        self.timmar = self.window.findChild(QLineEdit, 'timmar')
        self.minuter = self.window.findChild(QLineEdit, 'minuter')
        self.sekunder = self.window.findChild(QLineEdit, 'sekunder')
        self.textmsg = self.window.findChild(QLineEdit, 'textmsg')
        self.textmsg.setText("Hello")
  
        btn = self.window.findChild(QPushButton, 'pushButton')
        btn.clicked.connect(self.ok_handler)
        self.window.show()
 
         
    def ok_handler(self):
        print("started")
        x=datetime.today()
        self.timmar.setText(str(x.hour))
        self.minuter.setText(str(x.minute))
        self.sekunder.setText(str(x.second + 5))
        
        timmarValue = int(self.timmar.text())       
        minuterValue = int(self.minuter.text())
        sekunderValue = int(self.sekunder.text())
         
        y=x.replace(day=x.day+1, hour=timmarValue, minute=minuterValue, second=sekunderValue, microsecond=0)
        delta_t=y-x
 
        secs=delta_t.seconds+1
 
        t = Timer(secs, self.hello_world)
        t.daemon = True
        t.start()
         
    def hello_world(self):
        textmsg = self.textmsg.text()   
        print (textmsg)
         
        msgBox = QMessageBox(QMessageBox.Information, "QMessageBox Example", \
                                f"Message box pop up window\n{textmsg}", \
                                QMessageBox.Ok | QMessageBox.Cancel)
 
        returnValue = msgBox.exec()
        if returnValue == QMessageBox.Ok:
           print('OK clicked')
         
if __name__ == '__main__':
    app = QApplication(sys.argv)
    form = Form('/tmp/time2gui.ui')
    sys.exit(app.exec_())

Hmm strange can it be something wrong with pyside2? I noticed same code for the qmessage works if i use a button to trigger it instead of the timer.
Reply
#6
btw why do you use a python Timer instead of QTimer ??

I think Qt warns not to use python threading in conjunction with QT and use QThread instead -- which would include QTimer since it creates a separate process thread to run the timer within.
Reply
#7
(Feb-11-2020, 07:53 PM)Denni Wrote: btw why do you use a python Timer instead of QTimer ??

I think Qt warns not to use python threading in conjunction with QT and use QThread instead -- which would include QTimer since it creates a separate process thread to run the timer within.

I didn't know about it. Do you know any good tutorials about it?
Reply
#8
The QTimer is fairly straight forward just look it up QTimer
Reply
#9
(Feb-11-2020, 08:32 PM)darktitan Wrote: I didn't know about it. Do you know any good tutorials about it?

This is an timer example showing current time

from  PyQt5.QtCore import Qt, QTimer, QMetaObject
from PyQt5 import QtWidgets as qtw
import os, sys, datetime
from time import gmtime, strftime, time

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(210, 120)
        MainWindow.setWindowTitle("Time")

        MainWindow.isChanged = True

        btn_start = qtw.QPushButton(MainWindow)
        btn_start.setGeometry(10, 40, 90, 26)
        btn_start.setText("start Timer")
        btn_start.setObjectName("btn")
        btn_start.clicked.connect(self.button_start_clicked)

        btn_stop = qtw.QPushButton(MainWindow)
        btn_stop.setGeometry(110, 40, 90, 26)
        btn_stop.setText("stop Timer")
        btn_stop.setObjectName("btn_stop")
        btn_stop.clicked.connect(self.button_stop_clicked)

        self.label = qtw.QLabel(MainWindow)
        self.label.setAlignment(Qt.AlignCenter)
        self.label.setGeometry(10, 10, 200, 26)
        self.label.setObjectName("label")

        btn_info = qtw.QPushButton(MainWindow)
        btn_info.setGeometry(60, 80, 90, 26)
        btn_info.setText("info")
        btn_info.setObjectName("btn_info")
        btn_info.clicked.connect(self.msgbox)

        self.timer = QTimer()
        self.timer.timeout.connect(self.update_label)

        btn_start.setFocus()

        QMetaObject.connectSlotsByName(MainWindow)
        MainWindow.show()

    def update_label(self):
        current_time = "Time: " + str(datetime.datetime.now().time().strftime('%H:%M:%S'))
        import time
        start_time = time.time()
        # your script
        elapsed_time = time.time() - start_time
        self.label.setText(str(start_time))
        time.sleep(1)
        self.label.setText(current_time)

    def button_start_clicked(self):
        self.label.setText("starting Timer ...")
        self.timer.start(1000)  #  1 sekunde

    def button_stop_clicked(self):
        self.timer.stop()
        self.label.setText("Timer stopped")

    def msgbox(self):
        msg = qtw.QMessageBox()
        msg.setIcon(qtw.QMessageBox.Information)
        msg.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen)
        msg.setText("This is a message box")
        msg.setInformativeText("This is additional information")
        msg.setWindowTitle("MessageBox demo")
        msg.setDetailedText("The details are as follows:")
        msg.setStandardButtons(qtw.QMessageBox.Ok)
        msg.setDefaultButton(qtw.QMessageBox.Ok)
    
        retval = msg.exec_()

class MyWindow(qtw.QMainWindow):
    def closeEvent(self,event):
        event.accept()


if __name__ == "__main__":
    import sys
    app = qtw.QApplication(sys.argv)
    MainWindow = MyWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    sys.exit(app.exec_())
Reply
#10
Hey @Axel_Erfurt if you going to give an example why provide something that does not fully reflect proper design?
I mean it was a nice example and while not the ugliest I have seen it sure was not pretty either.

And if your defense is you were modifying the OP's code you should have gone the few extra minutes it would taken to clean it up ;)

Also @darktitan I would strongly suggest you stop using the Designer to create your GUI as you are only going to eventually experience a lot of pain with that methodology and frankly its just as easy and quick to design the GUI using proper Qt rather that what the Designer puts out since the Designer was not meant for that purpose.

Here is the previous example cleaned-up and made a bit more python-pyqt-ish

from PySide2.QtCore    import Qt, QTimer
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget
from PySide2.QtWidgets import QVBoxLayout, QHBoxLayout
from PySide2.QtWidgets import QPushButton, QLabel, QMessageBox

from datetime import datetime as dtDateTime
from time     import sleep    as tmSleep

class CentralPanel(QWidget):
    def __init__(self) :
        QWidget.__init__(self)

        self.StartTime = 0
        self.ElpseTime = 0

        self.btnStart = QPushButton()
        self.btnStart.setText('Start Timer')
        self.btnStart.clicked.connect(self.StartTimer)

        self.btnStop = QPushButton()
        self.btnStop.setText('Stop Timer')
        self.btnStop.clicked.connect(self.StopTimer)
        
        HBox1 = QHBoxLayout()
        HBox1.addStretch(1)
        HBox1.addWidget(self.btnStart)
        HBox1.addStretch(1)
        HBox1.addWidget(self.btnStop)
        HBox1.addStretch(1)

        self.lblTimeOut = QLabel('Timer Display')
        self.lblTimeOut.setAlignment(Qt.AlignCenter)

        self.btnInfo = QPushButton()
        self.btnInfo.setText('Info')
        self.btnInfo.clicked.connect(self.ShowMsg)

        HBox2 = QHBoxLayout()
        HBox2.addStretch(1)
        HBox2.addWidget(self.btnInfo)
        HBox2.addStretch(1)
        
        VBox = QVBoxLayout()
        VBox.addWidget(self.lblTimeOut)
        VBox.addLayout(HBox1)
        VBox.addLayout(HBox2)
        VBox.addStretch(1)

        self.setLayout(VBox)

        self.btnStart.setFocus()

        self.timer = QTimer()
        self.timer.timeout.connect(self.UpdateLabel)

    def StartTimer(self):
        self.StartTime = dtDateTime.now()

        self.lblTimeOut.setText('Starting Timer ...')
        self.timer.start(1000)  #  1 second

    def StopTimer(self):
        if self.ElpseTime == 0:
            self.ElpseTime = dtDateTime.now() - self.StartTime
        else:
            self.ElpseTime = self.ElpseTime + (dtDateTime.now() - self.StartTime)

        self.timer.stop()
        self.lblTimeOut.setText('Timer Stopped')
        tmSleep(2)
        self.lblTimeOut.setText('Timer Display')

    def UpdateLabel(self):
        CurTime = dtDateTime.now()
        DsplyTime = 'Time: ' + CurTime.strftime('%H:%M:%S')
        self.lblTimeOut.setText(DsplyTime)

    def ShowMsg(self):
        Msg = QMessageBox()
        Msg.setIcon(QMessageBox.Information)
        Msg.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.SplashScreen)
        Msg.setText('Showing Current Elasped Time')
        Msg.setInformativeText('This is the total amount of elapsed run time')
        Msg.setDetailedText('The Elapsed Time Is: ' + str(self.ElpseTime))
        Msg.setStandardButtons(QMessageBox.Ok)
        Msg.setDefaultButton(QMessageBox.Ok)
     
        Msg.exec_()
 
class MyWindow(QMainWindow):
    def __init__(self) :
        QMainWindow.__init__(self)

        self.setWindowTitle('Time Tracker')
        self.resize(210, 120)
        CenterPane = CentralPanel()
        self.setCentralWidget(CenterPane)
    
if __name__ == '__main__':
    MainEvntHndlr = QApplication([])

    MainApp = MyWindow()
    MainApp.show()

    MainEvntHndlr.exec()
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
Bug [PyQt] Qt app won't crash after sys.excepthook override Alfalfa 3 2,614 Dec-28-2020, 01:55 AM
Last Post: deanhystad
  [PyQt] Customizing QMessageBox arbiel 1 6,160 Dec-16-2020, 08:57 PM
Last Post: Axel_Erfurt
  PY TO EXE CRASH kozaizsvemira 0 2,250 Oct-19-2019, 07:27 PM
Last Post: kozaizsvemira
  (pyQt/pySide)setStyleSheet(border…) makes QPushButton not clickable in Maya vladlenPy 0 4,697 Apr-15-2018, 12:41 PM
Last Post: vladlenPy
  [PyQt] SOLVED QMessageBox: can't get QMessageBox.Yes to work Fred Barclay 0 5,515 May-18-2017, 06:07 AM
Last Post: Fred Barclay

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020