I want to display some QTextEdits over my main window at arbitrary locations. Below is my first attempt. It doesn't quite work. If I create the text edits before I show the window, the text edits appear, but if I create them after I have shown the window they don't appear. What's up with that? How can I get the ones created later to show up?
import sys, random
from PyQt4 import QtGui, QtCore
app = QtGui.QApplication(sys.argv)
win = QtGui.QMainWindow()
win.resize(500,500)
def new_text():
print "new text"
text = QtGui.QTextEdit(win)
text.move(random.random() * 400, random.random() * 400)
for i in range(3):
new_text()
timer = QtCore.QTimer()
timer.connect(timer, QtCore.SIGNAL("timeout()"), new_text)
timer.start(500)
win.show()
app.exec_()
Oh, I got it. You have to call show on each widget before it appears. I guess QMainWindow.show recursively calls the method for all of its children. So just add text.show() to the end of the new_text function and it works.
Related
Im trying to make a small app that would help me rename pictures. Since i want to manually order them, i had the idea to simply show a window with thumbnails inside in a grid ( or small scale images, doesnt matter ), and then drag and drop reorder them as i see fit. Afterwards its just click a button and they get properly named acording to the order.
Is there any container or something that would allow its inside widgets to be moved around like that while also properly displaying the inside widgets?
The ways im thinking of currently since i cant find anything else, is to make the whole background a canvas, move x/y on drag/drop of the pictures and then calculate where im dropping it off and manually reorder the whole canvas again and keep redrawing.
Im open to different python solution if anyone has them, but after checking wxwidgets and tkinter, i havent found anything that would be a solution to this without a lot of manual code.
After ekhumoro hint, i was able to solve it.
Heres a sample code that reads the current folder of its files, shows them as "thumbnails", and allows reordering.
#!/usr/bin/python
import sys, os
from PyQt5.QtWidgets import (QListWidget, QWidget, QMessageBox,
QApplication, QVBoxLayout,QAbstractItemView,QListWidgetItem )
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QSize, Qt
from PyQt5.QtWidgets import QListView
class Example(QWidget):
def __init__(self):
super().__init__()
self.icon_size = 200
self.initUI()
def loadImageItem(self, fajl,folder=None):
icon = QIcon()
item = QListWidgetItem()
if folder is not None:
pot = os.path.join(folder,fajl)
else:
pot = fajl
icon.addFile(pot,size=QSize(self.icon_size,self.icon_size))
item.setIcon(icon)
item.setTextAlignment(Qt.AlignBottom)
return item
def initUI(self):
vbox = QVBoxLayout(self)
listWidget = QListWidget()
#make it icons
listWidget.setDragDropMode(QAbstractItemView.InternalMove)
listWidget.setFlow(QListView.LeftToRight)
listWidget.setWrapping(True)
listWidget.setResizeMode(QListView.Adjust)
listWidget.setMovement(QListView.Snap)
listWidget.setIconSize(QSize(200,200))
folder = os.getcwd()
#folder = "/mnt/Data/pictures/2022-10-30 Sveta Katarina/izbor/1"
files = os.listdir(folder)
files = [f for f in files if os.path.isfile(os.path.join(folder,f))]
for foo in files:
listWidget.addItem(self.loadImageItem(foo,folder=folder))
vbox.addWidget(listWidget)
self.setLayout(vbox)
self.setGeometry(10, 10, 1260, 820)
self.setWindowTitle('Image renamer')
self.show()
def main():
App = QApplication(sys.argv)
ex = Example()
sys.exit(App.exec())
if __name__ == '__main__':
main()
I've been trying to figure this one out, the reason I don't want to use a layout is because the widgets scale with the window when resizing and I want them to stay put, I have made it where I can drag and drop the widgets but with them being in a layout it messes it up, please can someone help me figure this out.
I Want to be able to add lets say a label widget, I want to have it where I can press a button and it will create a new label widget in my window, I have done this part already but I want to be able to add widgets without the layout.
You just have to set another widget that is part of the window (or the window itself) as parent and make it visible with the show method:
import random
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Add", self)
button.clicked.connect(self.handle_clicked)
self.resize(640, 480)
def handle_clicked(self):
pos = QtCore.QPoint(*random.sample(range(400), 2))
label = QtWidgets.QLabel(self)
label.move(pos)
label.setText("{}-{}".format(pos.x(), pos.y()))
label.show()
def main():
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
I need help figuring out how to use the value written in a textbox in PyQT5, and use that value to build an IF statement. Any suggestions on how to do it? I have tried to declare the text in the textbox as a variable and use it in the IF statement but I can't seem to figure it out how to do it properly, and every time i run the code, some exit code shows (-1073741819 (0xC0000005) ).
Summing up, can't use pass the value of the textbox to the variable in order to do an IF statement.
I had this code down below:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QTextEdit
def window():
app = QApplication(sys.argv)
win = QMainWindow()
win.setGeometry(200, 200, 400, 400)
win.setWindowTitle("Register Program")
label = QtWidgets.QLabel(win)
label.setText("Random Text")
label.move(169, 15)
label2 = QtWidgets.QLabel(win)
label2.resize(300, 100)
label2.setText("1- Register new person\n2- See all regestries\n3- See last regestry\n\nPress ESC to exit\n")
label2.move(70, 50)
textbox = QtWidgets.QLineEdit(win)
textbox.setText("")
textbox.resize(250, 25)
textbox.move(70, 250)
button1 = QtWidgets.QPushButton(win)
button1.move(150, 300)
button1.setText("Submit")
button1.clicked.connect(clicked)
button2 = QtWidgets.QPushButton(win)
button2.move(150, 335)
button2.setText("Close")
button2.clicked.connect(close)
win.show()
sys.exit(app.exec_())
def clicked():
inpt = int(window().textbox.text)
if inpt == 1:
print("Hello")
def close():
sys.exit()
window()```
If you're just looking to get user input, there's a builtin static method you can call for requesting input of a particular type: https://doc.qt.io/qt-5/qinputdialog.html#getText
If you want to make your own widget however, you need to use the signals and slots to trigger a python method to store the value. This is easiest to do in a class. You can trigger the method whenever the text changes with the textChanged signal and do whatever you need to do with it.
(Note, I haven't run this as I don't have PyQt5 currently installed, but it should work)
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
# type: (QtWidgets.QWidget) -> None
super(Widget, self).__init__(parent)
self.line_edit = QtWidgets.QLineEdit()
main_layout = QtWidgets.QVBoxLayout()
main_layout.addWidget(self.line_edit)
self.setLayout(main_layout)
self.line_edit.textChanged.connect(self.on_text_changed)
def get_text(self):
return self.line_edit.text()
def on_text_changed(self, text):
print("The text was changed to:", text)
if __name__ == '__main__':
app = QtWidgets.QApplication([])
widget = Widget()
widget.show()
app.exec_()
Edit: Also, to clarify why you're getting an error, QApplication is a singleton. This means there can only ever be one created. If you try to create a second, you'll get an error. The best way to access the current QApplication is to call QApplication.instance(). You also only call app.exec_() once, as once the application is running it will continue to run in the background. You should use signal/slots to interact with the UI and trigger the code you want to run.
#!/usr/bin/env python3
from PyQt5.QtGui import *
from PyQt5.QtWidgets import QApplication, QWidget
import sys
app = QApplication(sys.argv)
screen = QApplication.primaryScreen()
widget = QWidget()
screenshot = screen.grabWindow(0, 0, 0, 100, 100)
screenshot.save('shot', 'jpg')
How can i use this to get a window? it only get a part of screen:
screenshot = screen.grabWindow( widget.winId() )
I need a crossplataform method..
Ref: http://doc.qt.io/qt-5/qscreen.html#grabWindow
You say you require a screenshot of a window, therefore
screenshot = screen.grabWindow(0, 0, 0, 100, 100)
is not the appropriate call here, since it captures the entire screen, cropped according to the final 4 parameters. (the 100 parameters are width and height).
screenshot = screen.grabWindow( widget.winId() )
captures the widget window. However, the reason you don't perhaps get what you expected on this call is that you don't create a solid widget and/or the widget hasn't been shown. Try the following example, making sure the app is on your primary display before clicking the button.
from PyQt5 import QtWidgets
import sys
app = QtWidgets.QApplication(sys.argv)
w = QtWidgets.QWidget()
grab_btn=QtWidgets.QPushButton('Grab Screen')
def click_handler():
screen = QtWidgets.QApplication.primaryScreen()
screenshot = screen.grabWindow( w.winId() )
screenshot.save('shot.jpg', 'jpg')
w.close()
grab_btn.clicked.connect(click_handler)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(grab_btn)
w.setLayout(layout)
w.show()
sys.exit(app.exec_())
I've tested this on Windows.
If any one is coming here and having issues with the other answer, it might be a timing problem.
If you try to grab a screenshot directly during / after initializing the QWidget() instead of at the press of a button it might just make a screenshot of your desktop at the area of your window.
So if you want to grab a screenshot directly after calling __init__, call it after waiting some time with a QTimer (do not use time.sleep() as this would block the GUI).
def initUI(self):
(...)
QTimer.singleShot(1000, self.saveScreenshot)
def saveScreenshot(self):
screen = QApplication.primaryScreen()
screenshot = screen.grabWindow(self.winId() )
screenshot.save('screenshot.png', 'png')
I'm working on a small application for work w/ python and PyQt4 for the GUI. What I'm trying to accomplish is having a tabbed GUI where when a user clicks on a menu item, the action taken adds a tab to the QTabWidget. I'm currently having trouble getting an action to do such a thing. I've tried creating the GUI by hand and with QT designer, but I cant figure out how, if at all possible, to get an action to add a tab to the QTabWidget. This is my python code:
import sys
from PyQt4 import QtGui, uic
class TestGUI(QtGui.QMainWindow):
def __init__(self):
super(TestGUI, self).__init__()
uic.loadUi('TEST.ui', self)
self.show()
self.actionAdd_Tab.triggered.connect(addTab)
def addTab():
print 'This works'
#Add new tab to GUI
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = TestGUI()
sys.exit(app.exec_())
Pressing the menu item prints 'This works' to the console, so I know that its calling the addTab() function, but how do I get it to add a Tab?
Let me know if you would like to see the .ui file if it will help
The handler for your action needs to create a tab label, and also a widget for the contents of the tab, so that they can be added to the tabwidget.
As a start, try something like this:
import sys
from PyQt4 import QtGui, uic
class TestGUI(QtGui.QMainWindow):
def __init__(self):
super(TestGUI, self).__init__()
uic.loadUi('TEST.ui', self)
self.actionAdd_Tab.triggered.connect(self.handleAddTab)
def handleAddTab(self):
contents = QtGui.QWidget(self.tabWidget)
layout = QtGui.QVBoxLayout(contents)
# add other widgets to the contents layout here
# i.e. layout.addWidget(widget), etc
self.tabWidget.addTab(contents, 'Tab One')
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = TestGUI()
window.show()
sys.exit(app.exec_())
QTabWidget's addTab() method, coincidentally named the same, adds a tab.