Show QMainwindow in the middle of the screen - pyqt4

I want show my project main window in the middle of the screen . when i call "self.show()" then the window show in the middle of the screen .

I know you have already solved it, but I make this answer for those who have the same question. I post it mainly because you asked for pyQt and the other answer is for Qt (C++).
I found a workaround here: https://bashelton.com/2009/06/pyqt-center-on-screen/
Is so simple and works perfectly, I transmit it..
class ExampleWindow (QtGui.QMainWindow):
def __init__ (self, parent=None):
'''constructor'''
QtGui.QMainWindow.__init__(self, parent)
self.setGeometry(0, 0, 650, 550)
self.setWindowTitle("My Example Application")
self.centerOnScreen()
def centerOnScreen (self):
'''centerOnScreen()
Centers the window on the screen.'''
resolution = QtGui.QDesktopWidget().screenGeometry()
self.move((resolution.width() / 2) - (self.frameSize().width() / 2),
(resolution.height() / 2) - (self.frameSize().height() / 2))
Good luck!

First I would recommend against trying to force a window position on your users and let the system's window manager decide where it should go. If you really insist on positioning it yourself (perhaps you are programming for a kiosk), you can find some information here in a previous question on stackoverflow.
A slightly more elegant calculation for doing this is discussed here.
When doing this calculation, it is important that it is done at the correct time, after Qt has resized everything and just before it is shown on screen. One method that might help is to create a one-shot timer and do the screen positioning in the slot for the timer.

This worked for me in Pyqt5:
from PyQt5.QtWidgets import *
qtRectangle = self.frameGeometry()
centerPoint = QDesktopWidget().availableGeometry().center()
qtRectangle.moveCenter(centerPoint)
self.move(qtRectangle.topLeft())

Related

Maximize figures before saving

The question about how to do maximize a window before saving has been asked several times and has several questions (still no one is portable, though), How to maximize a plt.show() window using Python
and How do you change the size of figures drawn with matplotlib?
I created a small function to maximize a figure window before saving the plots. It works with QT5Agg backend.
import matplotlib.pyplot as plt
def maximize_figure_window(figures=None, tight=True):
"""
Maximize all the open figure windows or the ones indicated in figures
Parameters
----------
figures: (list) figure numbers
tight : (bool) if True, applies the tight_layout option
:return:
"""
if figures is None:
figures = plt.get_fignums()
for fig in figures:
plt.figure(fig)
manager = plt.get_current_fig_manager()
manager.window.showMaximized()
if tight is True:
plt.tight_layout()
Problems:
I have to wait for the windows to be actually maximized before using the plt.savefig() command, otherwise it is saved with as not maximized. This is a problem if I simply want to use the above function in a script
(minor problems:)
2. I have to use the above function twice in order to get the tight_layout option working, i.e. the first time tight=True has no effect.
The solution is not portable. Of course I can add all the possible backend I might use, but that's kind of ugly.
Questions:
how to make the script wait for the windows to be maximized? I don't want to use time.sleep(tot_seconds) because tot_seconds would be kind of arbitrary and makes the function even less portable
how to solve problem 2 ? I guess it is related to problem 1.
is there a portable solution to "maximize all the open windows" problem?
-- Edit --
For problem 3. #DavidG suggestion sounds good. I use tkinter to automatically get width and height, convert them to inches, and use them in fig.set_size_inches or directly during the figure creation via fig = plt.figure(figsize=(width, height)).
So a more portable solution is, for example.
import tkinter as tk
import matplotlib.pyplot as plt
def maximize_figure(figure=None):
root = tk.Tk()
width = root.winfo_screenmmwidth() / 25.4
height = root.winfo_screenmmheight() / 25.4
if figure is not None:
plt.figure(figure).set_size_inches(width, height)
return width, height
where I allow the figure to be None so that I can use the function to just retrieve width and height and use them later.
Problem 1 is still there, though.
I use maximize_figure() in a plot function that I created (let's say my_plot_func()) but still the saved figure doesn't have the right dimensions when saved on file.
I also tried with time.sleep(5) in my_plot_func() right after the figure creation. Not working.
It works only if a manually run in the console maximize_figure() and then run my_plot_func(figure=maximized_figure) with the figure already maximized. Which means that dimension calculation and saving parameters are correct.
It does not work if I run in the console maximize_figure() and my_plot_func(figure=maximized_figure) altogether, i.e. with one call the the console! I really don't get why.
I also tried with a non-interactive backend like 'Agg', so that the figure doesn't get actually created on screen. Not working (wrong dimensions) no matter if I call the functions altogether or one after the other.
To summarize and clarify (problem 1):
by running these two pieces of code in console, figure gets saved correctly.
plt.close('all')
plt.switch_backend('Qt5Agg')
fig = plt.figure()
w, h = maximize_figure(fig.number)
followed by:
my_plot_func(out_file='filename.eps', figure=fig.number)
by running them together (like it would be in a script) figure is not saved correctly.
plt.close('all')
plt.switch_backend('Qt5Agg')
fig = plt.figure()
w, h = maximize_figure(fig.number)
my_plot_func(out_file='filename.eps', figure=fig.number)
Using
plt.switch_backend('Agg')
instead of
plt.switch_backend('Qt5Agg')
it does not work in both cases.

Stuck in infinite loop after destroying parent window (python, Tkinter)

The problem I am encountering is that I appear to be stuck in an infinite loop, (If I am not, please correct me). I am using tkinter for python 3.6 (64 bit) on windows 10.
In the module I am having an issue with I have 3 entry widgets and 2 buttons. Both buttons call the "destroy()" function in order to kill the parent window.
Below is a heavily abstracted version of my module, the purpose of the module is to take inputs from the entry widget and write them to a file.
def Create():
parent = Tk()
parent.MakeItlookNice
entry1 = Entry(parent)
entry1.insert(INSERT, "Please enter your desired username here")
entry2 = Entry(parent)
entry2.insert(INSERT, "Please enter your desired password here")
entry3 = Entry(parent)
entry3.insert(INSERT, "What is your mother's maiden name")
Submit = tk.Button(parent,
text ="Click here to submit your stuff",
command = lambda: [parent.destroy(),
submit.function()])
Cancel = tk.Button(parent,
text ="Click here to cancel your request",
command = lambda: parent.destroy())
parent.mainloop()
This function is contained within the module "RegisterNewUser". The "Menu" module is the module that called this function. As far as I am aware once parent.destroy() is called there is no more code to execute since it is all contained within parent.mainloop(), therefore the function is finished and the "Menu" module should continue executing.
What should happen:
I want the Submit button to destroy the window, execute the function and then return to the "Menu" module.
I want the cancel button to destroy the window and return to the "Menu" module.
What actually happens:
The window closes, like it is supposed to
But the code inside the "Menu" module does not start executing again
When I go to close the python shell, it warns me that the program is still running
Ultimately my question is, what code is still running and why hasn't it stopped?
Thank you for reading this and if you require more detail please let me know.
EDIT: I have done research on this topic before posting this question. I have read the documentation on both the tk.destroy() function and the tk.mainloop() function, I have also opened up the Tkinter module in IDLE to try and understand what happens at a deeper level but after all this, I was still unable to figure out a solution. This is my first question on stack overflow, please forgive me if I have done anything wrong.
Hmmm, so you say multiple windows? an easier way to achieve a complex UI as such is using a concept called frames. Tkinter allows you to completely change you screen and layout if you switch to a new frames. This might require you to reprogram alot of code. for an example see Switch between two frames in tkinter
Also, Some guy built a really nice Bitcoin monitoring app using tkinter and frames on youtube
I think you would probably benefit from using Toplevel() here.
I have taken the code you provided and added it to a class used to create the main window and to manage the pop up window.
I noticed a few things with you code.
Its obvoious you are importing tkinter twice like this:
import tkinter as tk
from tkinter import *
I can tell from how you have written your entry fields vs your buttons. Do not do this. Instead just used one or the other. I recommend just using import tkinter as tk.
You are using a function to create a new tkinter instance and judging by your question you all ready have a tkinter instance created for your menu. Instead of creating new Tk() instances you can use Toplevel() instead to open a new window that can inherit everything from the main window and should be easier to manage.
You do not really need to use lambda in this situation. I have also removed the lambda function and replaced with a simple command that will work here.
Take a look at the below code and let me know if you have any questions.
import tkinter as tk
class MyApp(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
self.master = master
self.master.title("Main MENU")
tk.Button(self.master, text="Open top level", command = self.create).pack()
def create(self):
self.top = tk.Toplevel(self.master)
entry1 = tk.Entry(self.top, width = 35)
entry1.pack()
entry1.insert(0, "Please enter your desired username here")
entry2 = tk.Entry(self.top, width = 35)
entry2.pack()
entry2.insert(0, "Please enter your desired password here")
entry3 = tk.Entry(self.top, width = 35)
entry3.pack()
entry3.insert(0, "What is your mother's maiden name")
tk.Button(self.top, text ="Click here to submit your stuff",
command = self.Submit).pack()
tk.Button(self.top, text ="Click here to cancel your request",
command = self.top.destroy).pack()
def Submit(self):
print("Do something here to submit data")
self.top.destroy()
if __name__ == "__main__":
root = tk.Tk()
app1 = MyApp(root)
tk.mainloop()
You can use toplevel() and its library function wait_window() just prior to (or instead of) your mainloop() and your problem will be solved
wait_window() mentioned above worked for me in the code below replacing popup.mainloop() with it, the mainloop() kept my code in an infinite loop upon the popup even after okay button was hit

Pyglet hello world example doesn't show label until a key is pressed

import pyglet
window = pyglet.window.Window()
label = pyglet.text.Label("Hello World!",
font_name="Times New Roman",
color=(255,255,255,255),
font_size=36,
x=window.width//2, y=window.height//2,
anchor_x="center", anchor_y="center")
#window.event
def on_draw():
window.clear()
label.draw()
pyglet.app.run()
This code is taken from the pyglet tutorial at https://pyglet.readthedocs.io/en/pyglet-1.2-maintenance/programming_guide/quickstart.html but when run it doesn't draw the label until any key is pressed. I added the color as I thought the text may have defaulted to black.
Am I missing something really obvious as to why this behaviour is happening?
OK, having had my memory jogged by the comments, I installed the MS Fonts and it now works in python 2.x but I still need to press a key to see the text in python 3. Maybe the font thing is a red-herring and there is some incompatibility with python 3.
As mentioned in the comments.
Most examples found on the internet (even most guides) assume a Windows platform.
If there's a font= declaration with a Windows font but you're running Linux, make sure you got the proper fonts installed or revert to a font you've got installed.
$ fc-list
Also not declaring a font will work too:
label = pyglet.text.Label("Hello World!",
color=(255,255,255,255),
font_size=36,
x=window.width//2, y=window.height//2,
anchor_x="center", anchor_y="center")
Because Pyglet will default to sans-serif:
If you do not particularly care which font is used, and just need to display some readable text, you can specify None as the family name, which will load a default sans-serif font (Helvetica on Mac OS X, Arial on Windows XP)
Your issue is probably that you don't manually update the screen after you drew something. Normally when you press a key, it forces a window.flip(), which basically means update the screen content.
window.clear() also triggers this behavior, but x.draw() does not. Why? Well the thing that takes time in computer graphics is not really the calculations, it's the updating them to the screen that takes time.. There for .draw() doesn't update the screen, it just puts the stuff in the graphical buffer ("page"), you decide when to flip the page and show the new buffer on the screen.
Try this out:
#window.event
def on_draw():
window.clear()
label.draw()
window.flip()
This might be a overkill solution, but it will probably solve the problem.
This overrides the default loop of pyglet and the default draw behavior, it's also one of the classes i use the most in my pyglet projects since it gives me the option to create my own framework.
import pyglet
class Window(pyglet.window.Window):
def __init__(self):
super(Window, self).__init__(vsync = False)
self.sprites = {}
self.sprites['testlabel'] = label = pyglet.text.Label("Hello World!",
color=(255,255,255,255),
font_size=36,
x=self.width//2, y=self.height//2, #self here, being pyglet.window.Window that we've inherited and instanciated with super().
anchor_x="center", anchor_y="center")
self.alive = 1
def on_draw(self):
self.render()
def render(self):
self.clear()
for sprite_name, sprite_obj in self.sprites.items():
sprite_obj.draw()
self.flip()
def on_close(self):
self.alive = 0
def run(self):
while self.alive:
self.render()
# This is very important, this queries (and empties)
# the pyglet event queue, if this queue isn't cleared
# pyglet will hang because it can't input more events,
# and a full buffer is a bad buffer, so we **NEED** this!
event = self.dispatch_events()
win = Window()
win.run()
It's extremely basic, but you can add more sprites, objects and render them in def render(self):.

wxPython from Linux to Windows

I have a wxPython application developed on Linux that I wish to deploy on Windows machines. While most of the things work well on porting there are small (but catastrophic) problems, none of which seem related. Rather than list them all, I'll start with one.
I have an array of images that I read in and place in a GridBagSizer in a Class. Unfortunately, the 'Bind' statement doesn't seem to take effect, and when I double-click on an image 'onSuitDClick' is not called.
suitSizer=SuitDisplay(self, suit
def onSuitDClick(self, event):
print 'sc'
class SuitDisplay(wx.Panel):
def __init__(self, frame, suit):
wx.Panel.__init__(self, frame, id=wx.ID_ANY)
suitSizer=wx.GridBagSizer(1, 13)
suitList=[]
for ii in range(0, len(g.CARDS)):
if g.CARDS[ii]+g.SUITS[suit] in frame.availableCards:
card=g.CARDS[ii]+g.SUITS[suit]
suitList.append(card)
for ii in range(0, len(suitList)):
card= suitList[ii]
image = wx.Bitmap(frame.imageFolder+card+'.png',wx.BITMAP_TYPE_PNG).ConvertToImage()
img = wx.StaticBitmap(self, -1, image.ConvertToBitmap(), name=card)
img.Bind(wx.EVT_LEFT_DCLICK, frame.onSuitDClick)
suitSizer.Add(img, pos=(0,cardPos), flag=wx.LEFT, border=border)
self.SetSizer(suitSizer)
Needless to say, this works perfectly in Linux.
Can anyone suggest where I might look for a solution?

How do I set the minimum size of a Gtk ButtonBox child?

I'm trying to set the minimum size of the buttons in this GtkButtonBox. Currently they seem to be fixed - approx 85 pixels I think.
Is this possible?
If not, is there another way in Gtk to get two small sized buttons to snuggle together like in the above picture rather than having them appear to be two separate buttons? For example GtkStackSwitcher may be something I could use but there doesn't appear to be a way to respond to click events for a button.
I've used this test program to create the above (Ubuntu 14.04, Gtk+3.10 and Python3):
from gi.repository import Gtk
import sys
class MyWindow(Gtk.ApplicationWindow):
def __init__(self, app):
Gtk.Window.__init__(self, title="example", application=app)
self.set_default_size(350, 200)
self.set_border_width(10)
hbox = Gtk.ButtonBox.new(Gtk.Orientation.HORIZONTAL)
hbox.set_layout(Gtk.ButtonBoxStyle.EXPAND)
button = Gtk.Button(label="a")
hbox.add(button)
button2 = Gtk.Button(label="b")
hbox.add(button2)
self.add(hbox)
class MyApplication(Gtk.Application):
def __init__(self):
Gtk.Application.__init__(self)
def do_activate(self):
win = MyWindow(self)
win.show_all()
def do_startup(self):
Gtk.Application.do_startup(self)
app = MyApplication()
exit_status = app.run(sys.argv)
sys.exit(exit_status)
With regards to a question about the desktop environment I'm using.
I've tried Mate, Unity and Gnome-Shell. All work the same way. I've removed the title and those controls. Still the same thing happens. To me this looks more like a GTK issue.
I believe that GtkButtonBox imposes some layout constraints on its buttons that you may not want here. Try using buttons in just a regular GtkGrid, but give them the GTK_STYLE_CLASS_LINKED CSS class.
For each button, do:
button.get_style_context().add_class(Gtk.STYLE_CLASS_LINKED)

Resources