Unwanted window appears - pyqt

I've written a short class to create a new window, with a tab menu, and a canvas on one of them. Every time I launch the app two windows show up. One of them is the wanted one, the other one is an empty one. I'm new to OOP in python, I guess I miss something in my class.
class Window(QtGui.QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.tab1 = QtGui.QWidget()
self.tab2 = QtGui.QWidget()
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.canvas)
self.tab1.setLayout(self.layout)
self.tabs = QtGui.QTabWidget()
self.tabs.addTab(self.tab1, "Database")
self.tabs.addTab(self.tab2, "Current")
self.tabs.show()

My mistake was here:
if __name__=='__main__':
app=QtGui.QApplication(sys.argv)
main = GUI.Window()
#main.show()
app.exec_()
The main.show() cause the problem.

Related

Is there an elegant way to delete a widget in QScrollArea in PyQt?

I am learning PyQt5 recently and have problems when I want to delete a widget in QScrollArea. Is there an elegant way to visit the element in QScrollArea and delete it when the "delete" button in that element is clicked? Thank you for any help!
class MyWidget(QWidget):
def __init__(self, id):
super().__init__()
self.layout = QHBoxLayout()
self.layout.addWidget(QPlainTextEdit(id))
self.layout.addWidget(QPushButton('Delete'))
self.setLayout(self.layout)
# connect options
connect_options()
def connect_options(self):
pass
class MyList(QScrollArea):
def __init__(self):
super().__init__()
self.layout = QVBoxLayout()
self.widget = QWidget()
for x in range(10):
self.layout.addWidget(MyWidget(str(x)))
self.widget.setLayout(self.layout)
self.setMinimumSize(1024, 500)
self.setWidget(self.widget)
First I would suggest you look into QListWidget, It will provide you various functions to handle situations like this.
for your problem, you will need to delete the widget from its parent layout & then delete it from the GUI
class MyWidget(QWidget):
def __init__(self, id):
super().__init__()
self.layout = QHBoxLayout()
self.layout.addWidget(QPlainTextEdit(id))
del_btn = QPushButton('Delete')
del_btn.clicked.connect(self._delete) # connect the click event to your delete function
self.layout.addWidget(del_btn)
self.setLayout(self.layout)
# connect options
self.connect_options()
def connect_options(self):
pass
def _delete(self):
# here you will delete your widget
parent_layout = self.parent().layout()
parent_layout.removeWidget(self) # remove the widget from its parent layout
self.deleteLater() # lets Qt knows it needs to delete this widget from the GUI
del self

How to put the window in the top left corner with PyQt?

I'm trying to put my window in the top left corner by runing the following code:
import sys
from PyQt5 import QtGui
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.resize(640, 480)
self.topLeft()
self.show()
def topLeft()(self):
frameGm = self.frameGeometry()
topLeftPoint = QApplication.desktop().availableGeometry().topLeft()
frameGm.moveTopLeft(topLeftPoint)
self.move(frameGm.topLeft())
def main():
app = QApplication(sys.argv)
mainWindow = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
But doing so, I get a gap between my window and the left-side of the screen like this :
Do you know where it comes from and how to prevent it?
This happens because when a window is shown the first time on the screen, some things (lots, actually) happen between show() and the moment where the window is actually mapped on the screen.
In order to achieve what you want, you need to delay the movement by some amount of time (usually, on "cycle" of the event loop is enough). Using a single shot QTimer with 1 timeout is normally fine.
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.initUI()
def initUI(self):
self.resize(640, 480)
QTimer.singleShot(1, self.topLeft)
self.show()
def topLeft(self):
# no need to move the point of the geometry rect if you're going to use
# the reference top left only
topLeftPoint = QApplication.desktop().availableGeometry().topLeft()
self.move(topLeftPoint)

Python Tkinter destroy window with a method

I'm a new student to Python, I'm sorry if my code is horrible. I'm trying to run a GIF animation of "loading" while the web scrape takes place. The issue is I cant get the toplevel window to destroy after the scrape completes.
I have looked at many videos and other posts on here none have worked. toplevel.destroy() seems to be the common suggestion but its not working.
my main window
class App:
def __init__(self, parent):
self.parent = parent
self.parent.geometry('1000x500+100+100')
self.parent.resizable(width=False, height=False)
self.parent.title('Class Project')
self.canvas1 = tkinter.Canvas(parent, height=500, width=1000)
filename = ImageTk.PhotoImage(file = "background.png")
background_label = tkinter.Label(self.canvas1, image=filename)
background_label.image = filename
The new window
def new_window(self):
self.newWindow = tkinter.Toplevel()
self.app = LoadingScreen(self.newWindow)
class LoadingScreen:
def __init__(self, parent):
self.parent = parent
self.parent.title('Loading....')
self.parent.geometry('350x270+100+100')
self.parent.resizable(width=False, height=False)
self.canvas = tkinter.Canvas(parent)
self.canvas.pack()
after the scrape I call the close
LoadingScreen.close_window()
def close_window():
toplevel.destory()
toplevel.destory()
NameError: name 'toplevel' is not defined
So far every thing works, just can not get the window to close.

Using dynamically added widgets in PyQt/Pyside

I have modified the answer given here as written below. The code is basically creating pushbuttons with a counter as pushButton_0, pushButton_1..
Here, I know that when I press to self.addButton I am creating widgets named like self.pushButton_0, self.pushButton_1 etc. So, my question is, how I'm supposed to use this pushbuttons? Because when I'm trying to do something like self.pushButton_0.clicked.connect(self.x), it' s telling me that "there is no attribute named 'pushButton_0'".
Thanks!
from PyQt4 import QtGui, QtCore
import sys
class Main(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Main, self).__init__()
self.GUI()
def GUI(self):
self.count = 0
# main button
self.addButton = QtGui.QPushButton('button to add other widgets')
self.addButton.clicked.connect(self.addWidget)
# scroll area widget contents - layout
self.scrollLayout = QtGui.QFormLayout()
# scroll area widget contents
self.scrollWidget = QtGui.QWidget()
self.scrollWidget.setLayout(self.scrollLayout)
# scroll area
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
# main layout
self.mainLayout = QtGui.QVBoxLayout()
# add all main to the main vLayout
self.mainLayout.addWidget(self.addButton)
self.mainLayout.addWidget(self.scrollArea)
# central widget
self.centralWidget = QtGui.QWidget()
self.centralWidget.setLayout(self.mainLayout)
# set central widget
self.setCentralWidget(self.centralWidget)
def addWidget(self):
self.scrollLayout.addRow(Test(self))
self.count = self.count + 1
print(self.count)
class Test(QtGui.QWidget):
def __init__( self, main):
super(Test, self).__init__()
self.Main = main
self.setup()
def setup(self):
print(self.Main.count)
name = "pushButton_"+str(self.Main.count)
print(name)
self.name = QtGui.QPushButton('I am in Test widget '+str(self.Main.count))
layout = QtGui.QHBoxLayout()
layout.addWidget(self.name)
self.setLayout(layout)
app = QtGui.QApplication(sys.argv)
myWidget = Main()
myWidget.show()
app.exec_()
After hours, I found the problem!
You have to declare the signal while creating the pushbutton!
To fix this, I rewrote the setup function as below;
def setup(self):
print(self.Main.count)
name = "pushButton_"+str(self.Main.count)
print(name)
self.name = QtGui.QPushButton('I am in Test widget '+str(self.Main.count))
self.name.clicked.connect(self.x) # self.x is any function
layout = QtGui.QHBoxLayout()
layout.addWidget(self.name)
self.setLayout(layout)
So know, you will run function x whenever you push the new created pushbuttons!

Python 3 Tkinter Borderless fullscreen application

I have been having a problem whilst creating a Python 3 tkinter application. I am currently developing using a Mac OSX system, but I normally use a Windows OS system.
I would like the application to occupy the entire screen without the Window Manager's titlebar and frame being around the application, often referred to a Fullscreen Borderless Window in gaming.
I have tried using root.attributes("-fullscreen", True) with root.overrideredirect(True) and root.wm_attributes("-topmost", 1). However the inclusion of the root.overrideredirect(True) line doesn't allow it to go proper fullscreen; it still shows the Mac Dock and Taskbar, and it also breaks my keystroke bindings in the application. Without the root.overrideredirect(True) line, the application does go into full screen mode (hiding the dock and the task bar), but the window does not fill the entire screen; it leaves a gap at the bottom, and it also retains the window manager's title bar and frame/border.
Here is an example of my code:
import tkinter as tk
class App(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Fullscreen Application")
self.pack(fill="both", expand=True, side="top")
self.parent.wm_state("zoomed")
self.parent.bind("<F11>", self.fullscreen_toggle)
self.parent.bind("<Escape>", self.fullscreen_cancel)
self.fullscreen_toggle()
self.label = tk.Label(self, text="Fullscreen", font=("default",120), fg="black")
self.label.pack(side="top", fill="both", expand=True)
def fullscreen_toggle(self, event="none"):
self.parent.focus_set()
self.parent.overrideredirect(True)
self.parent.attributes("-fullscreen", True)
self.parent.wm_attributes("-topmost", 1)
def fullscreen_cancel(self, event="none"):
self.parent.overrideredirect(False)
self.parent.attributes("-fullscreen", False)
self.parent.wm_attributes("-topmost", 0)
self.centerWindow()
def centerWindow(self):
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
w = sw*0.7
h = sh*0.7
x = (sw-w)/2
y = (sh-h)/2
self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))
if __name__ == "__main__":
root = tk.Tk()
App(root).pack(side="top", fill="both", expand=True)
root.mainloop()
I hope that someone is able to help! Thank you!
EDIT: I have just tested this on my Windows computer. Without the self.parent.overrideredirect(True), it creates the app and works perfectly as desired (fullscreen without window manager border or title bar). This must just be an OSX problem.
To fix your OS-X Problem i will provide a solution that fixes a similar problem for me. (Had some Issues using fullscreen in between Linux and Windows)
You wanted to get rid of the Window Managers Bar? Take a look at the docs it states an option that removes the window managers items by using -toolwindow option.
Concerning the size of your Application here is what helped me using linux - a "manual zoom":
class MyClass(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.overrideredirect(True) # depending on your needs
self.attributes("-toolwindow", 1) # this line removes the window managers bar
try: # Automatic zoom if possible
self.wm_state("zoomed")
print("Using automatic zoom")
except tk.TclError: # Manual zoom
# Bad Argument Error is a TclError
print("Using manual zoom")
# get the screen dimensions
width = self.winfo_screenwidth()
height = self.winfo_screenheight()
# build a geometry string.
# form: width x height + x_offset + y_offset
geom_string = "%dx%d+0+0" % (width, height)
self.wm_geometry(geom_string)
Please note that I am not using an unconfigured tk.Tk() - Instance here - my class is the tk.Tk() - Instance. So I do not need to overwrite the parent but only "myself" speaking of the POV of the class.
#!/usr/bin/python
import Tkinter as tk
class App(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("Fullscreen Application")
self.pack(fill="both", expand=True, side="top")
self.parent.wm_state("zoomed")
self.parent.bind("<F11>", self.fullscreen_toggle)
self.parent.bind("<Escape>", self.fullscreen_cancel)
self.fullscreen_toggle()
self.label = tk.Label(self, text="Fullscreen", font=("default",120), fg="black")
self.label.pack(side="top", fill="both", expand=True)
def fullscreen_toggle(self, event="none"):
self.parent.focus_set()
self.parent.overrideredirect(True)
self.parent.overrideredirect(False) #added for a toggle effect, not fully sure why it's like this on Mac OS
self.parent.attributes("-fullscreen", True)
self.parent.wm_attributes("-topmost", 1)
def fullscreen_cancel(self, event="none"):
self.parent.overrideredirect(False)
self.parent.attributes("-fullscreen", False)
self.parent.wm_attributes("-topmost", 0)
self.centerWindow()
def centerWindow(self):
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
w = sw*0.7
h = sh*0.7
x = (sw-w)/2
y = (sh-h)/2
self.parent.geometry("%dx%d+%d+%d" % (w, h, x, y))
if __name__ == "__main__":
root = tk.Tk()
App(root).pack(side="top", fill="both", expand=True)
root.mainloop()

Resources