How do I make the timer/clock move by the seconds? - python

this is my code, when i run it, it doesnt act like a clock. all it does it return a string. but what i wanted was the time moving by the seconds. help will be appreciated thank you
def DateTime(self):
dateandtime = QDialog()
dateandtime.setWindowTitle("Date and Time")
hbox = QHBoxLayout()
datetime = QDateTime.currentDateTime()
show = datetime.toString(Qt.DefaultLocaleLongDate)
label = QLabel(show)
label.setFont(QtGui.QFont("Arial", 10))
hbox.addWidget(label)
dateandtime.setLayout(hbox)

There should be a more elegant way, but find an example with a timer:
from PyQt5.QtWidgets import QDialog, QHBoxLayout, QLabel, QApplication
from PyQt5.QtCore import QDateTime, Qt, QTimer
from PyQt5 import QtGui
import sys
class Dialog(QDialog):
def __init__(self):
QDialog.__init__(self)
datetime = QDateTime.currentDateTime()
show = datetime.toString(Qt.DefaultLocaleLongDate)
self.label = QLabel(show)
self.DateTime()
def DateTime(self):
# dateandtime = QDialog()
self.setWindowTitle("Date and Time")
hbox = QHBoxLayout()
self.label.setFont(QtGui.QFont("Arial", 10))
hbox.addWidget(self.label)
self.setLayout(hbox)
def tick(self):
datetime = QDateTime.currentDateTime().toString(Qt.DefaultLocaleLongDate)
self.label.setText(datetime)
app = QApplication(sys.argv)
dialog = Dialog()
dialog.show()
timer = QTimer()
timer.timeout.connect(dialog.tick)
timer.start(1000)
app.exec_()

Related

How to auto-resize a PySide6 app to the minimum size when decreasing a `pixmap`?

I use the following code to set a PySide6 app to the minimal possible size. This works fine when increasing the size of the widgets (set - to + in line 37), but not when decreasing it - in effect, the size of the windows does decrease, but it seems to be one step late.
I found a few workarounds, most notably in Qt Layout, resize to minimum after widget size changes, but none of what I tried seems to be working (and I have met other issues with app.processEvents(), which should be avoided anyway).
Edit: In the new code example below, I think the problem is the width of the QPushButton, which is calculated too late.
Interestingly, this width of the QPushButton is solved by the layout.setSizeConstraint(QLayout.SetFixedSize) workaround, but the window width is not.
app.processEvents() works for this example, but I see bad side effects on other signals when using it.
New code example:
from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (QApplication, QLabel, QLayout, QMainWindow,
QPushButton, QVBoxLayout, QWidget)
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.i = 0
self.button = QPushButton("push me!")
self.button.clicked.connect(self.clicked)
self.label = QLabel()
layout = QVBoxLayout()
layout.addWidget(self.button)
layout.addWidget(self.label)
# https://stackoverflow.com/a/21458822/880783
# layout.setSizeConstraint(QLayout.SetFixedSize) # (ineffective)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)
self.clicked()
self.show()
def clicked(self):
npix = 500 - 50 * self.i
self.label.setPixmap(QPixmap(npix, npix))
# app.processEvents() # (effective, but discouraged)
self.adjustSize()
self.i += 1
app = QApplication()
win = Window()
app.exec()
Original code example:
import threading
import time
from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QLayout,
QMainWindow,
QWidget,
)
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.label = QLabel()
layout = QHBoxLayout()
layout.addWidget(self.label)
# https://stackoverflow.com/a/21458822/880783
# layout.setSizeConstraint(QLayout.SetFixedSize) # (ineffective)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)
self.show()
def run(self):
for i in range(10):
npix = 500 - 50 * i
self.label.setPixmap(QPixmap(npix, npix))
# app.processEvents() # (ineffective)
self.adjustSize()
time.sleep(1)
app = QApplication()
threading.Thread(target=Window().run).start()
app.exec()
#musicamante has posted very helpful comments, which I now turn into an answer.
Basically, this code works great:
from PySide6.QtCore import QMetaObject, Qt, QTimer, Slot
from PySide6.QtGui import QPixmap
from PySide6.QtWidgets import (QApplication, QLabel, QMainWindow, QPushButton,
QVBoxLayout, QWidget)
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.i = 0
self.button = QPushButton("push me!")
self.button.clicked.connect(self.clicked)
self.label = QLabel()
layout = QVBoxLayout()
layout.addWidget(self.button)
layout.addWidget(self.label)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
self.setWindowFlag(Qt.MSWindowsFixedSizeDialogHint)
self.clicked()
self.show()
# #Slot()
# def adjustSize(self):
# super().adjustSize()
def clicked(self):
npix = 500 - 50 * self.i
self.label.setPixmap(QPixmap(npix, npix))
self.i += 1
# # As in https://stackoverflow.com/a/23954088/880783 - does not work
# QMetaObject.invokeMethod(self, "adjustSize")
# This works!
QTimer.singleShot(0, self.adjustSize)
app = QApplication()
win = Window()
app.exec()
As one can see, I have also tried the approach put forward https://stackoverflow.com/a/23954088/880783 - without success, however.

Calculate a value and update this in a GUI python, without block my gui

I have a simple application, one label and 2 buttons ( start increment, stop increment), write in pyqt5.
When I pres start button want to see in ui, value update in real time and have acces at stop button.
Now when I press start button, not see an update in UI and when try to press on stop receive not responding.
One solution probably is Threads, but I don't understand how work thread's in Python
import sys
import time
from PyQt5 import QtWidgets, Qt
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QLineEdit
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
running = True
value = 1
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(600, 500))
self.setMaximumSize(QSize(600, 500))
self.setWindowTitle("Demo app")
QApplication.setStyle("fusion")
self.move(1000, 200)
self.button_start = QPushButton('Start', self)
self.button_start.setFixedHeight(40)
self.button_start.setFixedWidth(170)
self.button_start.move(10, 215)
self.button_start.clicked.connect(self.start_function)
self.update()
self.button_stop = QPushButton('Stop', self)
self.button_stop.setFixedHeight(40)
self.button_stop.setFixedWidth(170)
self.button_stop.move(200, 215)
self.button_stop.setDisabled(True)
self.button_stop.clicked.connect(self.stop_function)
self.update()
self.label = QLineEdit(self)
self.label.move(10, 170)
self.label.resize(170, 40)
self.label.setEnabled(False)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet("color: red;")
self.update()
def start_function(self):
self.button_start.setDisabled(True)
self.button_stop.setDisabled(False)
while self.running is True:
self.value += 1
self.label.setText(str(self.value))
print("Value: ", self.value)
time.sleep(1)
def stop_function(self):
self.running = False
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
mainWin.update()
sys.exit(app.exec_())
Maybe I'm a little late and you figured out yourself how to solve this problem, but for those with the same issue:
You can't set a loop in the GUI thread for this purpose, It will block the GUI thread from doing anything. Instead, You can use QTimer to schedule something to run at a later point in time. You can use it to implement something like a stopwatch.
Here is a functional minimal example:
import sys
import time
from PyQt5 import QtWidgets, Qt
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QLineEdit
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
value = 0
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(600, 500))
self.setMaximumSize(QSize(600, 500))
self.setWindowTitle("Demo app")
QApplication.setStyle("fusion")
self.move(1000, 200)
self.button_start = QPushButton('Start', self)
self.button_start.setFixedHeight(40)
self.button_start.setFixedWidth(170)
self.button_start.move(10, 215)
self.button_start.clicked.connect(self.start_function)
self.update()
self.button_stop = QPushButton('Stop', self)
self.button_stop.setFixedHeight(40)
self.button_stop.setFixedWidth(170)
self.button_stop.move(200, 215)
self.button_stop.setDisabled(True)
self.button_stop.clicked.connect(self.stop_function)
self.update()
self.label = QLineEdit(self)
self.label.move(10, 170)
self.label.resize(170, 40)
self.label.setEnabled(False)
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet("color: red;")
self.label.setText(str(self.value))
self.update()
self.workTimer = QTimer()
self.workTimer.setInterval(1000)
self.workTimer.timeout.connect(self.increase_value)
def start_function(self):
self.workTimer.start()
self.button_start.setDisabled(True)
self.button_stop.setDisabled(False)
def stop_function(self):
self.workTimer.stop()
self.button_start.setDisabled(False)
self.button_stop.setDisabled(True)
def increase_value(self):
self.value += 1
self.label.setText(str(self.value))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
mainWin.update()
sys.exit(app.exec_())

Line Animation with QPropertyAnimation

Trying to animate a line growing from nothing to a (0,0) to (200, 200) line with PyQt5 and using QPropertyAnimation. I already read a lot of documentation about Qt and tried several samples, but I just cannot get this to work. This is the code I have now:
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPainter, QPixmap, QPainterPath
from PyQt5.QtCore import QObject, QPointF, QPropertyAnimation, pyqtProperty
from PyQt5.QtCore import QLineF
import sys
class Sample(QWidget):
l1 = QLineF(QPointF(), QPointF())
def __init__(self):
super().__init__()
self.initView()
self.initAnimation()
def initView(self):
self.show()
def initAnimation(self):
self.anim = QPropertyAnimation(self.l1, b'geometry')
self.anim.setDuration(7000)
self.anim.setStartValue(QPointF(0, 0))
self.anim.setEndValue(QPointF(200, 200))
self.anim.start()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Sample()
sys.exit(app.exec_())
Not posting all previous attemps, each one fails with a different error. I got a fade out animation on a widget to work, and a picture following a path, but I can seem to make a simple line drawing work. I was hoping to achieve something like this:
Codepen example
Qt documentation is huge and it seems there are several ways to achieve this, painter and timer, animation, variant animation, but I am not very familiar with C++ and the translation to Python is not always easy. Also samples are not that easy to find.
Am I missing something obvious?
Thanks!
For the record, this is what I achieved so far but as soon as I un-comment the QPropertyAnimation creation, app does not launch. Anyway I was still far from the result in the accepted answer.
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class MyLine(QGraphicsLineItem, QObject):
def __init__(self):
super().__init__()
def _set_start(self, point):
self.setLine(point.x(), point.y(), self.line().p2().x(), self.line().p2().y())
def _set_end(self, point):
self.setLine(self.line().p1().x(), self.line().p1().y(), point.x(), point.y())
start = pyqtProperty(QPointF, fset=_set_start)
end = pyqtProperty(QPointF, fset=_set_end)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
hbox = QHBoxLayout(self)
self.button = QPushButton("Start", self)
self.button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
hbox.addWidget(self.button)
hbox.addSpacing(40)
self.line = MyLine()
self.line.setLine(0, 0, 10, 10)
scene = QGraphicsScene()
scene.addItem(self.line)
view = QGraphicsView(scene)
hbox.addWidget(view)
self.anim = QPropertyAnimation(self.line, b"end") # crash without error here
# self.anim.setDuration(2500)
# self.anim.setLoopCount(1)
# self.anim.setStartValue(QPointF(10, 10))
# self.anim.setEndValue(QPointF(200, 200))
# self.button.clicked.connect(self.anim.start)
self.setGeometry(300, 300, 380, 250)
self.setWindowTitle('Color anim')
self.show()
if __name__ == "__main__":
app = QApplication([])
ex = Example()
ex.show()
app.exec_()
You have to use QGraphicsView, QGraphicsScene with QGraphicsLineItem as I show below:
from PyQt5 import QtCore, QtGui, QtWidgets
class LineAnimation(QtCore.QObject):
def __init__(self, parent=None):
super(LineAnimation, self).__init__(parent)
self.m_line = QtCore.QLineF()
self.m_item = QtWidgets.QGraphicsLineItem()
self.m_item.setLine(self.m_line)
self.m_item.setPen(
QtGui.QPen(
QtGui.QColor("salmon"),
10,
QtCore.Qt.SolidLine,
QtCore.Qt.SquareCap,
QtCore.Qt.RoundJoin,
)
)
self.m_animation = QtCore.QPropertyAnimation(
self,
b"p2",
parent=self,
startValue=QtCore.QPointF(0, 0),
endValue=QtCore.QPointF(200, 200),
duration=5 * 1000,
)
self.m_animation.start()
def p1(self):
return self.m_line.p1()
def setP1(self, p1):
self.m_line.setP1(p1)
self.m_item.setLine(self.m_line)
def p2(self):
return self.m_line.p2()
def setP2(self, p2):
self.m_line.setP2(p2)
self.m_item.setLine(self.m_line)
p1 = QtCore.pyqtProperty(QtCore.QPointF, fget=p1, fset=setP1)
p2 = QtCore.pyqtProperty(QtCore.QPointF, fget=p2, fset=setP2)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(
scene, alignment=QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop
)
self.setCentralWidget(view)
line_animation = LineAnimation(self)
scene.addItem(line_animation.m_item)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())

How do I print in multiple QLabel when I click the PushButton?

How do I print in multiple QLabel when I click the PushButton?, because it only works in Quantity I also want it in Item Name and Price. I tried putting multiple print_click(self) it wont work it say redefinition of unused 'print_clink'. Thanks in advance
My Code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel, QLineEdit
from PyQt5.QtCore import pyqtSlot`
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.ItemName = QLabel('Item Name:')
self.Item_Line = QLabel('')
self.Item_Name = QLineEdit('')
self.PriceName = QLabel('Price:')
self.Price_Line = QLabel('')
self.Price_Name = QLineEdit('')
self.QuantityName = QLabel('Quantity:')
self.Quantity_Line = QLabel('0')
self.Quantity_Name = QLineEdit()
self.Update_button = QPushButton("Update")
self.Update_button.clicked.connect(self.print_click)
self.Clear_button = QPushButton("Clear")
self.Clear_button.clicked.connect(self.clear_click)
hbox = QHBoxLayout(self)
hbox.addWidget(self.ItemName)
hbox.addWidget(self.Item_Name)
hbox.addWidget(self.PriceName)
hbox.addWidget(self.Price_Name)
hbox.addWidget(self.QuantityName)
hbox.addWidget(self.Quantity_Line)
hbox.addWidget(self.Quantity_Name)
hbox.addWidget(self.Update_button)
hbox.addWidget(self.Clear_button)
self.show()
self.Clear_button.clicked.connect(self.Item_Line.clear)
self.Clear_button.clicked.connect(self.Item_Name.clear)
self.Clear_button.clicked.connect(self.Price_Line.clear)
self.Clear_button.clicked.connect(self.Price_Name.clear)
self.Clear_button.clicked.connect(self.Quantity_Line.clear)
self.Clear_button.clicked.connect(self.Quantity_Name.clear)
#pyqtSlot()
def print_click(self):
self.Quantity_Line.setText(self.Quantity_Name.text())
def clear_click(self):
self.Quantity_Line(self.Quantity_Name.text(''))
return self.Quantity
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())
I'm not completely sure of the expected result but I guess there are some mistakes and redundancies in your code :
the Price_Line and Item_Line weren't added to the QHBoxLayout
the method print_click wasn't setting the text from Price_Name and Item_Name on the respective Price_Line and Item_Line.
the clear_click method wasn't really useful as you already connected the clear method of every other elements on that button.
The following code is adapted from yours, paying attention to the points mentioned above :
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel, QLineEdit
from PyQt5.QtCore import pyqtSlot
class Window(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.ItemName = QLabel('Item Name:')
self.Item_Line = QLabel('')
self.Item_Name = QLineEdit()
self.PriceName = QLabel('Price:')
self.Price_Line = QLabel('')
self.Price_Name = QLineEdit()
self.QuantityName = QLabel('Quantity:')
self.Quantity_Line = QLabel('0')
self.Quantity_Name = QLineEdit()
self.Update_button = QPushButton("Update")
self.Update_button.clicked.connect(self.print_click)
self.Clear_button = QPushButton("Clear")
hbox = QHBoxLayout(self)
hbox.addWidget(self.ItemName)
hbox.addWidget(self.Item_Line)
hbox.addWidget(self.Item_Name)
hbox.addWidget(self.PriceName)
hbox.addWidget(self.Price_Line)
hbox.addWidget(self.Price_Name)
hbox.addWidget(self.QuantityName)
hbox.addWidget(self.Quantity_Line)
hbox.addWidget(self.Quantity_Name)
hbox.addWidget(self.Update_button)
hbox.addWidget(self.Clear_button)
self.show()
self.Clear_button.clicked.connect(self.Item_Line.clear)
self.Clear_button.clicked.connect(self.Item_Name.clear)
self.Clear_button.clicked.connect(self.Price_Line.clear)
self.Clear_button.clicked.connect(self.Price_Name.clear)
self.Clear_button.clicked.connect(self.Quantity_Line.clear)
self.Clear_button.clicked.connect(self.Quantity_Name.clear)
def print_click(self):
self.Price_Line.setText(self.Price_Name.text())
self.Item_Line.setText(self.Item_Name.text())
self.Quantity_Line.setText(self.Quantity_Name.text())
if __name__ == "__main__":
app = QApplication(sys.argv)
win = Window()
sys.exit(app.exec_())

Python PYQT Tabs outside app window [why]

Tabs added before app.exec_() is called look and act as any other tabs u met, though if adding another after the app.exec_() call makes the new tab 'detach' from the main app window. Pic below :)
Why? How can I make it move inside the window?
import threading
import time
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QFormLayout
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QTabWidget
from PyQt5.QtWidgets import QTextEdit
from PyQt5.QtWidgets import QWidget
class ATry(threading.Thread):
def __init__(self):
super().__init__()
def run(self):
time.sleep(1)
anotherTextEdit = QTextEdit()
anotherLineEdit = QLineEdit()
anotherLayout = QFormLayout()
anotherLayout.addRow(anotherTextEdit)
anotherLayout.addRow(anotherLineEdit)
anotherTab = QWidget()
anotherTab.setLayout(anotherLayout)
md.addTab(anotherTab, "Outside")
app = QApplication(sys.argv)
md = QTabWidget()
aTextEdit = QTextEdit()
aLineEdit = QLineEdit()
layout = QFormLayout()
layout.addRow(aTextEdit)
layout.addRow(aLineEdit)
thisTab = QWidget()
thisTab.setLayout(layout)
md.addTab(thisTab, "Inside")
a = ATry()
a.start()
md.show()
app.exec_()
Screen describing the problem
It works with QTimer or signals:
import sys
import time
from PyQt5.QtCore import QObject
from PyQt5.QtCore import QThread
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QFormLayout
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QTabWidget
from PyQt5.QtWidgets import QTextEdit
from PyQt5.QtWidgets import QWidget
class ATry(QThread):
def __init__(self, pointer):
super().__init__()
self.pointer = pointer
def run(self):
time.sleep(2)
self.pointer.emit()
def addTheTab():
anotherTextEdit = QTextEdit()
anotherLineEdit = QLineEdit()
anotherLayout = QFormLayout()
anotherLayout.addRow(anotherLineEdit)
anotherLayout.addRow(anotherTextEdit)
anotherTab = QWidget()
anotherTab.setLayout(anotherLayout)
md.addTab(anotherTab, "Whatever")
class MyQObject(QObject):
trigger = pyqtSignal()
def __init__(self):
super().__init__()
def connect_and_get_trigger(self):
self.trigger.connect(addTheTab)
return self.trigger
def getGFX(self):
app = QApplication(sys.argv)
md = QTabWidget()
md.show()
return app, md
obj = MyQObject()
app, md = obj.getGFX()
addTheTab()
a = ATry(obj.connect_and_get_trigger())
a.start()
# timer = QTimer()
# timer.timeout.connect(proba)
# timer.start(3000)
app.exec_()

Categories

Resources