How to make window look like a win10 widget. Python - python

I'm trying to create a windows app that shows weather like windows 10 widgets using Tkinter. The issue I ran into is that I cannot remove the window's border to make it look like a real widget.
Here's what it looks like and what I'd like to remove:
self.root.overrideredirect(1) kinda works but I still can minimize the window, which is what I do not want to be available.
That's what I want it to look and behave like:
To sum up:
How to disable window title and all of that on top properly?
How to move the window after, set the position of it on the screen?
I'm new to Python, any help is appreciated. Thank you all. Peace
To clarify: The app is supposed to be not affected by tab+alt (and other ways to minimize it) and be always on desktop, not on top of any other app, right on the desktop.
UPD
The thing I missed working around with win32gui is that I cannot get the handle the way I was trying to due to the fact that the code of getting the handle before the window itself was created (before mainloop) so root.wait_visibility() was the solution for me. After that I got the handle using EnumWindows and positioned my window the way I needed, finally disabling the border with root.overrideredirect. The suggested solutions will be tried as well. Thank you for help!
top-right corner of the desktop:

You can try this:
root.overrideredirect(1)
root.geometry('250x150+900+600')
#900+600 is x+y axis position of window
And for making close button like of widget you can make transparent frame in side, put button there and in command .destroy().
Edit
From TheLizzard's comment, visit here for further information. From there:
To make the window draggable, put bindings for (mouse clicks) and (mouse movements) on the window.
import tkinter
class Win(tkinter.Tk):
def __init__(self,master=None):
tkinter.Tk.__init__(self,master)
self.overrideredirect(True)
self._offsetx = 0
self._offsety = 0
self.bind('<Button-1>',self.clickwin)
self.bind('<B1-Motion>',self.dragwin)
def dragwin(self,event):
x = self.winfo_pointerx() - self._offsetx
y = self.winfo_pointery() - self._offsety
self.geometry('+{x}+{y}'.format(x=x,y=y))
def clickwin(self,event):
self._offsetx = event.x
self._offsety = event.y
win = Win()
win.mainloop()
You can use this for some part in top of the window rather then in whole window. By making new frame there implement it, to make your widget moveable.
And from second comment of TheLizzard, visit here for more information. From there:
If you want the window to stay above all other windows.
root.attributes("-topmost", True)

Related

Tkinter: Is there any way to remove the top bar of my program?

Okay, so i am using tkinter to make a GUI, i feel like the top bar looks kinda ugly so that's why i was planning to remove it and put some nice icons. I used this line of code to remove the top bar gui.overrideredirect(True) and it worked :D, but you can't move the program around the screen (it sticks to the top-left corner of the screen). Is there any other way i can do this without sticking my program to the corner? Thanks.
import requests
import tkinter as tk
#GUI Config
gui = tk.Tk()
gui.geometry('970x569')
gui.title("Zombs Royale Tools v1")
gui.resizable(False, False)
#Code below is the one i used to do this[![enter image description here][1]][1]
gui.overrideredirect(True)
#Background-image
bgImage = tk.PhotoImage(file="width.png")
background_label = tk.Label(gui, image = bgImage)
background_label.place(x=0,y=0,relwidth=1, relheight=1)
#GUI Widgets#
#Exit Button
exit_image = tk.PhotoImage(file="close.gif")
exit_button = tk.Button(gui, image=exit_image, borderwidth=0, command=gui.destroy)
exit_button.place(rely=0.01, relx=0.01)
Removing the titlebar is done with override redirect. However, this removes every window function as well. That includes moving the window around and resizing it.
This means with overrideredirect you can skip the
gui.resizable(False, False)
One thing you can do is provide more info for the window’s geometry:
gui.geometry('970x569+600+500')
The 2 last numbers provide the info regarding the positioning of your window on the desktop, in case you don’t want it to be spawned on the top left corner.
If you want to make the window movable you will have to integrate your own code. It has been discussed here before.
Eg.
here

Disable window move in Tkinter Python

it seems that I was pending to continue the bombardment of questions. It this is short, Is it possible to disable the movement of the Tkinter window without deleting the top bar of this?
It would give a minimal and reproducible code, but if it did it would only be two lines, it would be useless.
Bind a event for your window,and set the window .geometry()
But now you can not revise the window size by dragging the window's border(But it can maximize the window.).
Here is an example of the code:
import tkinter
def GetWindowPos():
global X,Y
X = win.winfo_geometry().split("+")[1]
Y = win.winfo_geometry().split("+")[2]
win.bind_all('<Configure>', HoldOn)
def HoldOn(event):
win.geometry("+{}+{}".format(X,Y))
win = tkinter.Tk()
win.geometry("400x400+{}+{}".format(12,12))
tkinter.Label(win,text="Halo!").grid()
win.after(100,GetWindowPos)
win.mainloop()
I have found a method, but as you might know to achieve something, we have to lose something!
You can use:
root.overrideredirect(True) # turns off title bar
by which you wont be able to move the tkinter window and also Tkinter application won't be displayed in taskbar, but you will also lose the title bar.
but if you wish to have the title bar,
then you can create one by this link.
Or use below to make a new title bar and also be able to move it(from this answer)
def move_window(event):
root.geometry('+{0}+{1}'.format(event.x_root, event.y_root)
# bind title bar motion to the move window function
title_bar.bind('<B1-Motion>', move_window)
But still your Tkinter application won't show up in taskbar, here's a solution(from this answer):
root = tkinter.Tk()
top = tkinter.Toplevel(root)
root.attributes("-alpha",0.0) # to make root invisible
#toplevel follows root taskbar events (minimize, restore)
def onRootIconify(event): top.withdraw()
root.bind("<Unmap>", onRootIconify)
def onRootDeiconify(event): top.deiconify()
root.bind("<Map>", onRootDeiconify)
You can add a toplevel window under the root object, make toplevel invisible and then handle the icon events of top level to hide or show the root window on taskbar.

Tkinter window not filling screen in zoomed state on secondary display

I'm building a small python 3 tkinter program on windows (10). From a main window (root) I'm creating a secondary window (wdowViewer). I want it to be full screen (zoomed) on my secondary display. The code below works on my main setup with two identical screens. If I however take my laptop out of the dock and connect it to (any) external display, the new window only fills about 2/3 of the secondary display.
Two things to note:
- The laptop and external monitor have same resolution.
- The window is appropriately zoomed when overrideredirect is set to 0.
mon_primary_width = str(app.root.winfo_screenwidth()) # width of primary screen
self.wdowViewer = Toplevel(app.root) # create new window
self.wdowViewer.geometry('10x10+' + mon_primary_width + '+0') # move it to the secondary screen
self.wdowViewer.wm_state('zoomed') # full screen
self.wdowViewer.overrideredirect(1) # remove tool bar
app.root.update_idletasks() # Apply changes
After two days of experimenting I finally found a fix.
Consider the following example: Making a toplevel zoomed, works fine on any secondary display when using the following code:
from tkinter import *
# Make tkinter window
root = Tk()
sw = str(root.winfo_screenwidth())
Label(root, text="Hello Main Display").pack()
# Make a new toplevel
w = Toplevel(root)
w.geometry("0x0+" + sw + "+0")
w.state('zoomed')
w.overrideredirect(1)
Label(w, text='Hello Secondary Display').pack()
root.mainloop()
However, in my code I'm making a new Toplevel after running the mainloop command. Then, the issue arises. A code example with the issue:
from tkinter import *
# New Tkinter
root = Tk()
sw = str(root.winfo_screenwidth())
# Function for new toplevel
def new_wdow():
w = Toplevel(root)
w.geometry("0x0+" + sw + "+0")
w.state('zoomed')
w.overrideredirect(1)
Label(w, text='Hello Secondary Display').pack()
# Make button in main window
Button(root, text="Hello", command=new_wdow).pack()
root.mainloop()
Problem: The bug is only present if the DPI scaling in Windows is not set to 100%. Hence, there seems to be a bug in how tkinter handles the DPI scaling subsequent to running mainloop. It does not scale the window properly, but Windows is treating it as if it does.
Fix: Tell Windows that the app takes care of DPI scaling all by itself, and to not resize the window. This is achievable using ctypes. Put the following code early in your python script:
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(2)
Hopefully others will find the solution helpful. Hopefully, someone may explain more of what is going on here!

Unclosable window using tkinter

Hey I am making a program that take a picture using my webcam when I type the wrong password. The program will be open and I want it unclosable.
I need to know how to make a window unclosable using tkinter.
You can try all of the many things #abarnert suggested, but I think the easiest way would be to just ignore the close event.
From this question:
Here you have a concrete example:
import Tkinter as tk
import tkMessageBox as messagebox
root = tk.Tk()
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
(edited code for Windows)
So change on_closing() to
def on_closing():
pass
and that makes it unclosable. I tried Alt+F4, the close button, closing it from the Windows Taskbar, all to no avail. The only way I was able to kill it was to use Task Manager.
Tkinter doesn't have any way to do this directly. But it does have something that may be good enough, or it may be too much overkill: the overrideredirect flag:
If non-zero, this prevents the window manager from decorating the window. In other words, the window will not have a title or a border, and it cannot be moved or closed via ordinary means.
That's not quite up-to-date; it may actually have a title or border on some platforms… but it won't be closable.
This is easy to use: just do root.overrideredirect(True) (or, if you want to do it to a different Toplevel window instead of your root, window.overrideredirect(True)).
But notice that it can't be moved or closed, not just that it can't be closed. (It also can't be resized, if you want that.)
So, the only thing you can do is set the flag, but then bind the mouse-button events to handle moving manually. For example, in your window's __init__ method:
self.overrideredirect(True) # if this is a Toplevel
#self.parent.overrideredirect(True) # if this is a Frame on root
self.bind('<ButtonPress-1>', self.move_start)
self.bind('<ButtonRelease-1>', self.move_end)
self.bind('<B1-Motion>', self.move_move)
And then:
def move_start(self, event):
self.startx, self.starty = event.x, event.y
def move_stop(self, event):
self.move_move(event)
def move_move(self, event):
x = self.winfo_x() + event.x - self.startx
y = self.winfo_y() + event.y - self.starty
self.geometry("+%s+%s" % (x, y))
Obviously, if you want any widgets within the window to accept clicks, you probably don't want to make the whole window a drag area. In fact, you may not want to make the whole window a drag area even if it doesn't have anything to click, because that's not really following Mac or Windows human interface guidelines. You could fake a grip area—a title bar, a border around the window, etc.—just by, e.g., adding a Label pinned to the side(s) you want to grip from and only binding there, or by creating a "child" window inset from the main window that steals the bindings. But this is never going to look like a "native" window.
If you really need a native window, but with the close box (the X in the top-right corner on Windows, the red dot in the top-left on Mac, etc.) disabled or missing (and, on Windows, with the "close" item on the window menu disabled, and Alt+F4, and so on, and similarly for X11…)… As far as I know, there's no cross-platform way to do that in Tkinter. You will have to write code for each platform that gets at the underlying native window objects and does native window things to them. At that point, you probably want to look at using a more powerful windowing library than Tkinter—e.g., I believe Qt, Gtk+, and wx all have much simpler ways of creating a normal window but with the close box disabled.

pygtk: how to force message dialogs to show up in the center of the screen?

I have a glade GUI and i'm using dome gtk.MessageDialog widgets created with pygtk for user interaction. My problem is that whenever I throw a dialog message on the screen, they show up all over the place. One might show up on the top right corner, the next on the bottom left, top left, mid left etc...
Is there a way to force these things to show up in the center of the screen or at the position where the parent window is at?
Never mind. Found the solution.
For others who might wander about the same thing, the solution to this problem lies in specifying a parent value to the gtk.MessageDialog construct.
If you are using a glade gui, in your class, and your glade xml is loaded in to a variable named 'gui', it would look like this:
#!/usr/bin/env/python
par = self.gui.get_widget('your_parent_window')
msg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK, parent=par)
if msg.run():
msg.destroy()
return None
Check out the reference material at PyGTK 2.0 Reference Manual
I have not had a chance to try this but MessageDialog seems to be derived from Window which has a set_position method.
This method accepts one of the following:
# No influence is made on placement.
gtk.WIN_POS_NONE
# Windows should be placed in the center of the screen.
gtk.WIN_POS_CENTER
# Windows should be placed at the current mouse position.
gtk.WIN_POS_MOUSE
# Keep window centered as it changes size, etc.
gtk.WIN_POS_CENTER_ALWAYS
# Center the window on its transient parent
# (see the gtk.Window.set_transient_for()) method.
gtk.WIN_POS_CENTER_ON_PARENT
None of the provided solutions will work if your parent window is not yet shown, that is if the messagedialog is to be shown during the instantiation of a class (your class, not the "parent" window class). During this time Gtk has not yet placed the window, even if code for messagedialog is after the code that shows the window. Which means your dialog box will be somehow "parentless" and the message dialog will appear wherever it likes...
My naive solution for that problem...
GObject.timeout_add(interval=50, function=self.stupid_dialog_1)
and
def stupid_dialog_1(self):
par = self.gui.get_widget('your_parent_window')
msg = gtk.MessageDialog(type=gtk.MESSAGE_INFO, buttons = gtk.BUTTONS_OK, parent=par)
# do anything here...
return False #stop the timer...

Categories