Pyqt5 Entry don't appear [duplicate] - python-3.x

This question already has answers here:
QLabel does not display in QWidget
(2 answers)
Closed 2 years ago.
I would like to create a simple GUI that assign to each name another name randomly. But the problem is that, after the user decide how many name create, it should show the QLineEdit tag, but i can't see that. There aren't errors. Obviusly,the application is not over. The problem is only the QLineEdit tag. Here there is the code:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import Qt
from PyQt5 import QtGui
import sys
class Assigner(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(0,0,250,500)
self.setWindowTitle("Assigner")
self.counter = 3
self.tit = QLabel(self)
self.tit.setText("Assigner GUI")
self.tit.move (60,10)
self.tit.setFont(QtGui.QFont("Times", 20, QtGui.QFont.Bold))
self.butup = QPushButton("↑",self)
self.butup.resize(40,40)
self.butup.setToolTip("Increase number")
self.butup.move(100,50)
self.butup.clicked.connect(self.increase)
self.lab = QLabel(self)
self.lab.setText(str(self.counter))
self.lab.resize(40,60)
self.lab.move (100,115)
self.lab.setStyleSheet("background: red;")
self.lab.setFrameShape(QFrame.Panel)
self.lab.setFrameShadow(QFrame.Sunken)
self.lab.setLineWidth(4)
self.lab.setFont(QtGui.QFont("Times", 20, QtGui.QFont.Bold))
self.butdo = QPushButton("↓",self)
self.butdo.resize(40,40)
self.butdo.setToolTip("Decrease number")
self.butdo.move(100,200)
self.butdo.clicked.connect(self.decrease)
self.go = QPushButton("Start assign",self)
self.go.resize(70,40)
self.go.setToolTip("Start")
self.go.move(85,280)
self.go.clicked.connect(self.start)
self.show()
def increase(self):
self.counter += 1
self.lab.setText(str(self.counter))
def decrease(self):
if self.counter > 0:
self.counter -= 1
self.lab.setText(str(self.counter))
def start(self):
self.go.deleteLater()
self.butdo.deleteLater()
self.butup.deleteLater()
self.lab.deleteLater()
self.tit.deleteLater()
self.entry = []
self.y = 20
for i in range(self.counter):
self.entry.append(QLineEdit(self))
self.entry[-1].move(20, self.y)
self.entry[-1].resize(220,40)
self.y += 50
if __name__ == "__main__":
app = QApplication(sys.argv)
ass = Assigner()
sys.exit(app.exec_())
When you click the start button, all is white, but we should see the QLineEdit.
If someone knows where is the issue, please write it to me

Your QLineEdits are simply invisible; just add:
self.entry[-1].show()
# or self.entry[-1].setVisible(True)
There's a (discrete) note about that in Qwidget's doc:
If you add a child widget to an already visible widget you must
explicitly show the child to make it visible.
So an alternative solution could be to self.hide() at the very beginning of start, modify your sub-widgets as before, and finish the function with a self.show().

Related

PyQt5: count seconds mouse is over QPushButton in tooltip

The following running code gives a window with a button on it . The tooltip displays when the mouse enters the button.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtTest import QTest
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.button = QPushButton("MyButton")
global i
i = 0
self.button.setToolTip(str(i) + " seconds has passed since you move your mouse onto MyButton")
self.button.leaveEvent = self.clear()
self.layout.addWidget(self.button)
timer = QTimer(self)
timer.timeout.connect(self.start_counting)
timer.start(1000)
self.widget = QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
def clear(self):
global i
i = 0
def start_counting(self):
if self.button.underMouse() == True:
global i
i = i + 1
self.button.setToolTip(str(i) + " seconds has passed since you move your mouse onto MyButton")
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )
My goal is to count the number of seconds the mouse is inside the button and live display it using the tooltip. More precisely, I need to make sure all of the following is happening:
Every time the mouse enters the button, the count starts at 0 seconds and the tooltip shows up.
While the mouse stays inside the button (stationary or moving), the tooltip stays shown with the number of seconds (the text displayed inside the tooltip) updated over time.
When the mouse leaves the button, the count is cleared to zero.
As seen in the code, I have attempted to use underMouse to achieve my goals. My attempt is a partial success as the tooltip does update itself when the mouse moves inside the button. However, the tooltip does not update itself when the mouse stays stationary inside the button. Also, the count does not seem to be cleared when the mouse moves outside of the button .
What am I missing ?
One solution is to use an event-filter to monitor the enter and leave events, and also use an elapsed-timer to get an accurate measure of how long the mouse has been over the target widget. Below is a basic demo based on your example that implements the above. It also tries to match the normal behaviour of tooltips, but if necessary you can easily adjust the code to suit your own needs:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.button = QPushButton("MyButton")
self.layout.addWidget(self.button)
self.widget = QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
self.position = QPoint()
self.counter = QElapsedTimer()
self.timer = QTimer()
self.timer.timeout.connect(self.start_counting)
self.button.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QEvent.Enter and source is self.button:
self.counter.start()
self.timer.start(1000)
QTimer.singleShot(500, self.start_counting)
elif event.type() == QEvent.Leave and source is self.button:
self.timer.stop()
QToolTip.hideText()
return super().eventFilter(source, event)
def start_counting(self):
if self.button.underMouse():
if not QToolTip.isVisible():
self.position = QCursor.pos()
count = int(self.counter.elapsed() / 1000)
QToolTip.showText(self.position, (
f'{count} seconds have passed since '
'you moved your mouse onto MyButton'
))
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )

I can't get the text data out of the PyQt5 label class. it only returns the last of the widget array [duplicate]

This question already has answers here:
lambda in for loop only takes last value [duplicate]
(3 answers)
Closed 3 years ago.
I can't get the text data out of the PyQt5 label class. my goal is given an array of labels if I press one I must return the text value contained. it only returns the last label of the array.
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def clickable(widget):
class Filter(QObject):
clicked = pyqtSignal()
def eventFilter(self, obj, event):
if obj == widget:
if event.type() == QEvent.MouseButtonRelease:
if obj.rect().contains(event.pos()):
self.clicked.emit()
# The developer can opt for .emit(obj) to get the object within the slot.
return True
return False
filter = Filter(widget)
widget.installEventFilter(filter)
return filter.clicked
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.setIU()
def setIU(self):
self.setCentralWidget(QtWidgets.QWidget(self))
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
label = []
for y in range(4):
label.insert(y,QLabel())
label[y].setMinimumSize(QtCore.QSize(160, 0))
label[y].setMaximumSize(QtCore.QSize(160, 95))
label[y].setStyleSheet("background-color:white;")
label[y].setText(str(y))
label[y].setObjectName("label"+str(y))
clickable(label[y]).connect(lambda: self.showText1(label[y]))
self.gridLayout.addWidget(label[y])
self.centralWidget().setLayout(self.gridLayout)
self.show()
def showText1(self,_hit):
num = _hit.text()
#Terminal Print
print ("Label "+num+" clicked")
#MessageBox
mes =QtWidgets.QMessageBox()
mes.setWindowTitle("Return")
mes.setText("Label "+num+" clicked")
mes.setIcon(QtWidgets.QMessageBox.Information)
mes.setStandardButtons(QtWidgets.QMessageBox.Ok)
mes.exec_()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
when I run the program: this is the window generated at startup
when I click the number 1 label but it returns:
when I click the label
what the Terminal returns: Terminal returns
You only need to change the lambda function definition:
clickable(label[y]).connect(lambda y=y: self.showText1(label[y]))

How to share data between two threads [duplicate]

This question already has answers here:
Call a function defined in another function
(4 answers)
Closed 3 years ago.
I am creating an application using Tkinter. I have two Threads, the first is an algorithm that looks for results and the second is my Tkinter window that displays the number of results found.
import time
from tkinter import *
from threading import Thread
global results
results = []
class thread(Thread):
def __init__(self, name):
Thread.__init__(self)
self.name = name
def run(self):
global results
if self.name == "algo":
algo()
elif self.name == "window":
window = Tk()
tmp = StringVar()
tmp.set(str(len(results)))
text = Label(window, textvariable=tmp, font=(None, 12))
text.place(x=10, y=15)
window.mainloop()
def algo():
global results
while True:
time.sleep(1)
results += [1]
print(len(results))
thread_1 = thread("algo")
thread_2 = thread("window")
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
The problem is that the textvariable does not update.
You can run the tkinter mainloop in the mainthread, and your function in a specially spawned new Thread. It does not appear necessary to have more:
import time
import tkinter as tk
from threading import Thread
def algo():
while True:
time.sleep(1)
result.set(result.get() + 1)
print(result.get())
root = tk.Tk()
result = tk.IntVar(value=0)
label = tk.Label(root, textvariable=result)
label.pack()
thread_1 = Thread(target=algo)
thread_1.start()
root.mainloop()

How do I thread a single method on a PyQt GUI so that the rest of the GUI is still accessible?

Basically, when the Switch Button is pressed, which is connected to the reconfigure method, I want everything in the reconfigure method to run as a separate thread/process so the main GUI is still accessible and not being blocked. Below is a watered down version of my code.
import sys, time
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import *
#//Popup Class - Will appear when the Switch Button is pressed
class Popup(QWidget):
def __init__(self):
QWidget.__init__(self)
#//nothing here now, it will have a message telling user to wait while program is run
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
grid = QtGui.QGridLayout()
label_header = QtGui.QLabel("TEST RECONFIGURE")
font = label_header.font()
font.setPointSize(24)
label_header.setFont(font)
#//Creating Static Labels that will be placed in the GUI
label_1 = QtGui.QLabel("Menu 1:")
label_2 = QtGui.QLabel("Menu 2:")
label_spacer = QtGui.QLabel("")
label_cfg = QtGui.QLabel("Current Configuration: '/tmp/directory_here' ")
global comboBox1
comboBox1 = QtGui.QComboBox()
comboBox1.addItem("1")
comboBox1.addItem("2")
global comboBox2
comboBox2 = QtGui.QComboBox()
comboBox2.addItem("3")
comboBox2.addItem("4")
#//Switch Button!!!
global switchButton
switchButton = QPushButton("Switch")
switchButton.clicked.connect(self.reconfigure)
quitButton = QtGui.QPushButton('Quit')
quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
#//Configure the grid layout
grid.addWidget(label_spacer, 0,0,9,9)
grid.addWidget(label_header, 0,0,1,6)
grid.addWidget(label_1, 1,0,1,1)
grid.addWidget(comboBox1, 2,0,1,1)
grid.addWidget(label_2, 3,0,1,1)
grid.addWidget(comboBox2, 4,0,1,1)
grid.addWidget(switchButton, 5,0,1,2)
grid.addWidget(label_cfg, 6,0,1,9)
grid.addWidget(quitButton, 9,9,1,1)
self.setLayout(grid)
self.setGeometry(640,300,400,600)
self.show()
#//open up the popup window for switch button, and reconfigure
def reconfigure(self):
print "Opening New Window"
self.w = Popup()
self.w.setGeometry(QRect(self.x()+100,self.y()+100,400,200))
self.w.show()
txt1 = str(comboBox1.currentText())
txt2 = str(comboBox2.currentText())
print " reconfiguring to option %s and option %s" %(txt1, txt2)
#
# This is where most of the work is done, and takes about 1/2 an hour for everything to run
# Want to make this method a separate thread/process so the rest of the main GUI is still accessible
# while the program is running as the whole class will be a separate tab in a larger GUI
#
print "all done!"
#//runner
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I feel like I have to use threading and signals to accomplish this, but I am not having much luck. Any help would be greatly appreciated. Thank you!
import sys, time
from PyQt4 import QtGui, QtCore
from PyQt4.Qt import *
class ConfigureThread(QtCore.QThread):
def run(self):
pass
#
# This is where most of the work is done, and takes about 1/2 an hour for everything to run
# Want to make this method a separate thread/process so the rest of the main GUI is still accessible
# while the program is running as the whole class will be a separate tab in a larger GUI
#
#//Popup Class - Will appear when the Switch Button is pressed
class Popup(QWidget):
def __init__(self):
QWidget.__init__(self)
#//nothing here now, it will have a message telling user to wait while program is run
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
grid = QtGui.QGridLayout()
label_header = QtGui.QLabel("TEST RECONFIGURE")
font = label_header.font()
font.setPointSize(24)
label_header.setFont(font)
#//Creating Static Labels that will be placed in the GUI
label_1 = QtGui.QLabel("Menu 1:")
label_2 = QtGui.QLabel("Menu 2:")
label_spacer = QtGui.QLabel("")
label_cfg = QtGui.QLabel("Current Configuration: '/tmp/directory_here' ")
global comboBox1
comboBox1 = QtGui.QComboBox()
comboBox1.addItem("1")
comboBox1.addItem("2")
global comboBox2
comboBox2 = QtGui.QComboBox()
comboBox2.addItem("3")
comboBox2.addItem("4")
#//Switch Button!!!
global switchButton
switchButton = QPushButton("Switch")
switchButton.clicked.connect(self.reconfigure)
quitButton = QtGui.QPushButton('Quit')
quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
#//Configure the grid layout
grid.addWidget(label_spacer, 0,0,9,9)
grid.addWidget(label_header, 0,0,1,6)
grid.addWidget(label_1, 1,0,1,1)
grid.addWidget(comboBox1, 2,0,1,1)
grid.addWidget(label_2, 3,0,1,1)
grid.addWidget(comboBox2, 4,0,1,1)
grid.addWidget(switchButton, 5,0,1,2)
grid.addWidget(label_cfg, 6,0,1,9)
grid.addWidget(quitButton, 9,9,1,1)
self.setLayout(grid)
self.setGeometry(640,300,400,600)
self.show()
#//open up the popup window for switch button, and reconfigure
def reconfigure(self):
print("Opening New Window")
self.w = Popup()
self.w.setGeometry(QRect(self.x()+100,self.y()+100,400,200))
self.w.show()
txt1 = str(comboBox1.currentText())
txt2 = str(comboBox2.currentText())
print(" reconfiguring to option %s and option %s" %(txt1, txt2))
self.th = ConfigureThread()
self.th.finished.connect(self.configuring_done)
self.th.start()
def configuring_done(self):
print("all done!")
#//runner
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

How to update QListWidget

How to update QLIstWidget to show items as when when it is added.
Like i am adding 100 QListWidgetItems to QListWidget in a loop. All these 100 items are visible only after loop is completed. But i want to know if is it possible to show item as and when the item is added.
I tried self.ListWidget.setUpdatesEnabled(True) but no luck.
Any help is appreciated.
you can repaint the listwidget in the loop:
def insertItem(self):
for i in range(1,100):
self.listWidget.addItem(str(i))
self.listWidget.repaint()
with QTimer you can control the delay between 2 items.
Edit: Perhaps i didn't understand your question correctly:
you can add all items, hide them and then set them visible item by item:
import sys
from PyQt5 import QtGui, QtCore, QtWidgets
class MyWidget(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.setGeometry(200,100,600,900)
self.listWidget = QtWidgets.QListWidget(self)
self.listWidget.setGeometry(20,20,100,700)
self.pushButton = QtWidgets.QPushButton(self)
self.pushButton.setGeometry(20,800,100,30)
self.pushButton.setText('show Items')
self.pushButton.clicked.connect(self.showItems)
self.timer = QtCore.QTimer()
for i in range(0,100):
self.listWidget.addItem(str(i))
self.listWidget.item(i).setHidden(True)
self.z = 0
def showItems(self):
self.timer.start(100)
self.timer.timeout.connect(self.nextItem)
def nextItem(self):
try:
self.listWidget.item(self.z).setHidden(False)
self.listWidget.repaint()
self.z += 1
except AttributeError:
self.timer.stop()
self.z = 0
app = QtWidgets.QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())
in pyqt4 replace 'QtWidgets' by 'QtGui'

Resources