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.
Related
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)
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
I have a tinter Toplevel window that I want to come up without a frame or a titlebar and slightly transparent, and then solid when the mouse moves over the window. To do this I am using both Toplevel.overrideredirect(True) and Toplevel.attributes('-alpha', 0.75). I am binding the <Enter> and <Leave> events to a function for this.
These all work when tried separately, but when I have the overrideredirect set to True, the bindings for the mouse entering and leaving no longer works. The binding calls when I click on the window, and then when I move the mouse, but not when the curser enter or leave the window.
I have also tried binding these to a Frame, but with no further luck.
toplevel = Toplevel(root)
toplevel.overrideredirect(True)
toplevel.attributes('-alpha', 0.75)
toplevel.bind('<Enter>', lambda x: mouseMovement(command='enter'))
toplevel.bind('<Leave>', lambda x: mouseMovement(command='leave'))
def mouseMovement(command):
print('Callback: ' + command)
if command == 'enter':
toplevel.attributes('-alpha', 1)
elif command == 'leave':
toplevel.attributes('-alpha', 0.75)
I have tried using the answer to the similar question here, but this results in a window that has all the standard OS decorations, but the close, minimise, and enlarge buttons are simply disabled. Is there a way where I can get rid of the titlebar, but still keep my bindings?
On X Windows this can be handled using appropriate Extended Window Manager Hints to request the window manager to decorate the toplevel the way desired. This sounds like a splash screen window so 'splash' is likely to be appropriate here. For this use the wm_attributes -type parameter eg:
toplevel.wm_attributes('-type', 'splash')
will have the toplevel decorated as for a splash screen dialog which usually means no title bar. If you apply this to an already mapped window, you will need to withdraw and re-map (call wm_deiconify) to get the window manager to apply its settings for the new hint type.
I have written an application in python 2.7 and tkinter. I created a tool bar with several buttons that open up respective top windows that display various options. I used ttk.Checkbutton with the 'toolbutton' style as an indicator to show whether the option windows are open or closed.
The problem is that the option windows will go to the back if another window is selected. Currently, if one selects the toolbutton again, the option window will close. However, I only want to close the window if it is on top. If the option window is not on top, I want the window to moved to the front.
Some of the code I have working:
class MainWindow:
def __init__(self,application):
self.mainframe=tk.Frame(application)
application.geometry("900x600+30+30")
self.otherOptionsSelect=tk.IntVar()
self.otherOptions_Button=ttk.Checkbutton(application,style='Toolbutton',variable=self.otherOptionsSelect,
onvalue=1, offvalue=0,image=self.optionsIcon, command=self.otherOptions)
def otherOptions(self):
if self.otherOptionsSelect.get()==0:
self.otherOptions.destroy()
return
self.otherOptions=tk.Toplevel()
self.otherOptions.title("IsoSurface Options")
self.otherOptions.geometry("200x165+"+str(int(application.winfo_x())+555)+"+"+str(int(application.winfo_y())+230))
self.otherOptApply_button=ttk.Button(self.otherOptions,text="Apply",command=self.showFrame)
self.otherOptApply_button.place(x=20,y=80,width=50,height=30)
self.otherOptClose_button=ttk.Button(self.otherOptions,text="Close",command=self.otherOptionsClose)
self.otherOptClose_button.place(x=80,y=80,width=50,height=30)
def otherOptionsClose(self):
self.otherOptionsSelect.set(0)
self.otherOptions.destroy()
Here is a picture of the entire application I have written:
In the above image, each window has their respective ttk.checkbutton. At the moment, toggling the checkbutton either opens or closes the window. However, what I really want it to do is close the window if the window is in front of the application, or bring the window to the front if it is behind the application.
Hopefully this clears some things up.
Thanks in advance!
It is in fact possible to check stacking order of windows. Using Tkinter, you have to do some funny tcl evals to get at the information. I found the answer at TkDoc in the section on Windows and Dialogs, scroll down until you get to "Stacking Order". The code baffled me until I started playing around with it interactively. My test code was:
import Tkinter as tk
root = tk.Tk()
root.title('root')
one = tk.Toplevel(root)
one.title('one')
two = tk.Toplevel(root)
two.title('two')
I then manipulated the windows so that two was on top, one under that and root below them all. In that configuration, the following weirdness can tell you relative layering of windows:
root.tk.eval('wm stackorder '+str(two)+' isabove '+str(root))
returns 1, meaning "Yes, window two is above window root." While the following:
root.tk.eval('wm stackorder '+str(root)+' isabove '+str(two))
returns 0, meaning "No, window root is not above window two." You can also use the command:
root.tk.eval('wm stackorder '+str(root))
Which gives back the full window stacking order in the form of a weird string something like this:
'. .68400520L .68401032L'
Which starts to make sense when you run the commands:
str(root)
str(one)
str(two)
and figure out that root has the internal name '.', one is '.68400520L' and two is '.68401032L'. You read the output of root.tk.eval('wm stackorder '+str(root)) backwards so it's saying two is on top, one is under that and root is below both.
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...