Tkinter windows decoration - python-2.7

I am using Tkinter for Building GUI for my python module but i don't want default windows title bar and border. I used "root.overrideredirect(True)" but with "overrideredirect()" I am losing control from my window like resizing and shifting from one place to another place. When ever I run my GUI its shows on top-left corner of my window.
from Tkinter import *
version = "v0.1"
def getinfo():
lab1 = Label(fram, text = "Your name :")
lab2 = Label(fram, text = "Your Password : ")
lab1.grid(row =1,sticky=W)
lab2.grid(row =2,sticky=W)
def Exit():
sys.exit(1)
def btn2():
btn_show = Button(fram,text = "Show")
btn_show.grid(row = 9, sticky = W)
btn_hide = Button(fram, text = "Hide")
btn_hide.grid(row = 9,column = 2, sticky = W)
root = Tk()
root.overrideredirect(True)
root.geometry("450x300")
fram = Frame(root)
fram.grid()
default_labels()
btn2()
root.mainloop()

Here is a basic example of how you can build your title bar and be able to move your window around. It is not perfect but should serve as a good starting point for your.
import Tkinter as tk
root = tk.Tk()
root.overrideredirect(True)
root.geometry("450x300")
root.config(background="darkblue")
root.columnconfigure(0, weight=1)
def move_event(event):
root.geometry('+{0}+{1}'.format(event.x_root, event.y_root))
title_frame = tk.Frame(root)
title_frame.grid(row=0, column=0, sticky="ew")
title_frame.columnconfigure(0, weight=1)
title_frame.bind('<B1-Motion>', move_event)
tk.Label(title_frame, text="Custom title bar").grid(row=0, column=0, sticky="w")
tk.Button(title_frame, text="-").grid(row=0, column=1, sticky="e")
tk.Button(title_frame, text="[]").grid(row=0, column=2, sticky="e")
tk.Button(title_frame, text="X", command=root.destroy).grid(row=0, column=3, sticky="e")
tk.Label(root, text="Test window!", fg="white", bg="darkblue").grid(row=1, column=0)
root.mainloop()
Results:
The resulting window can be dragged around though a little bit off as the window will want to move relative to the mouse position.

Yes, that's exactly what overrideredirect does. You will have to add your own bindings to allow for interactively moving and resizing the window.
The answer to the question Tkinter: windows without title bar but resizable shows how to add resizing.
The answer to the question Python/Tkinter: Mouse drag a window without borders, eg. overridedirect(1) shows how to handle the moving of the window.

Related

Panel size does not expand in a frame with a menu

I've created a frame with a menu bar in wxpython and set the main sizer as a child of the frame itself, but the frame's panel stays in a fixed size after resizing the frame. When removing the menu bar and setting the main sizer to the panel itself resizing works perfectly, but with the menu added to the frame setting the main sizer to the panel doesn't work.
tl;dr - the panel size for this code stays fixed. How do I make it resizable?
import wx
class Mainframe(wx.Frame):
def __init__(self,parent,title):
wx.Frame.__init__(self,parent,title=title,size=(650,450))
self.Main_Panel = wx.Panel(self,id=wx.ID_ANY)
#################################################################
### Template menubar menubar
#################################################################
Menubar = wx.MenuBar()
Filemenu = wx.Menu()
Debugmenu = wx.Menu()
self.Menu_Open_File = Filemenu.Append(wx.ID_OPEN,"Open","Open an nrix file to edit")
self.Menu_SaveAs_File = Filemenu.Append(wx.ID_SAVEAS,"Save as","Normal saving will be incorporated later")
Filemenu.AppendSeparator()
self.Menu_About_Dialog = Filemenu.Append(wx.ID_ABOUT,"About","Information about the program and changelog")
self.Debug_State_Switch = Debugmenu.Append(wx.ID_ANY,"Debug on","Turn on debug mode",wx.ITEM_CHECK)
Menubar.Append(Filemenu,"File")
Menubar.Append(Debugmenu,"Debug")
self.SetMenuBar(Menubar)
#################################################################
### Frame objects
#################################################################
Left_Static_text = wx.StaticText(self.Main_Panel,wx.ID_ANY,style=wx.ALIGN_LEFT)
Left_Static_text.SetFont(wx.Font(16,wx.ROMAN,wx.NORMAL,wx.FONTWEIGHT_NORMAL))
Left_Static_text.SetLabel("Exploitable text")
Left_Text_Control = wx.TextCtrl(self.Main_Panel,wx.ID_ANY,value="Exploitable")
Buttons = []
for i in range(4):
Buttons.append(wx.Button(self.Main_Panel,label=str(i + 1),size=(50,50)))
#################################################################
### Frame sizers
#################################################################
Grid_Sizer = wx.GridSizer(2,2,15,15)
Ver_Wrapper = wx.BoxSizer(wx.VERTICAL)
Left_Sizer = wx.BoxSizer(wx.VERTICAL)
Whole_Sizer = wx.BoxSizer(wx.HORIZONTAL)
#################################################################
### Attaching sizers
#################################################################
for i in range(4):
Grid_Sizer.Add(Buttons[i],0,wx.EXPAND)
Ver_Wrapper.Add((0,0),proportion=1,flag=wx.EXPAND)
Ver_Wrapper.Add(Grid_Sizer,proportion=0,flag=wx.CENTER)
Ver_Wrapper.Add((0,0),proportion=1,flag=wx.EXPAND)
Left_Sizer.Add((0,0),proportion=1,flag=wx.EXPAND)
Left_Sizer.Add(Left_Static_text,proportion=0,flag=wx.CENTER)
Left_Sizer.Add(Left_Text_Control,proportion=0,flag=wx.CENTER)
Left_Sizer.Add((0,0),proportion=1,flag=wx.EXPAND)
Whole_Sizer.Add(Left_Sizer,proportion=1,flag=wx.EXPAND)
Whole_Sizer.Add(Ver_Wrapper,proportion=3,flag=wx.EXPAND)
# self.Main_Panel.SetSizer(Whole_Sizer) <- THIS WORKS WITHOUT A MENU
self.SetSizer(Whole_Sizer)
app = wx.App(False)
frame = Mainframe(None,"Menu UI")
frame.Show(True)
app.MainLoop()
Turns out this is just a small glitch. When Whole_Sizer is attributed to Main_Panel in Windows, all of the widgets are positioned in the upper left corner. Once I started messing with the window size by dragging the window corner around the whole thing solved itself. Now I just feel stupid.

Cannot dynamically change font in python Tkinter text editor

Recently I have been working on a GUI python plain text editor. The code calls this function:
def TimesNewRoman():
global fontname
global font
fontname = "Times New Roman"
print font
The variables are:
fontname = "Calibri"
size = "14"
font = fontname + " " + size
And Tkinter reads the font with the code:
textPad.config(
borderwidth=0,
font=font ,
foreground="green",
background="black",
insertbackground="white", # cursor
selectforeground="blue", # selection
selectbackground="#008000",
wrap="word",
width=64,
undo=True, # Tk 8.4
)
However, I cannot get it to work. I get no errors but the font remains Calibri. I have searched the internet looking for anything that might allow me to dynamically change the font of the text canvas, but I have not succeeded in finding one that works. Any help in implementing a font modifying feature would be very much appreciated.
I am using python 2.7.7, Tkinter, and I am running this on Windows 7.
Your function should change the font name to "Times New Roman". Are you sure you are calling the function?
Just for completeness, as also Bryan Oakley stated, you should use the tuple syntax when specifying a font name with more than one word (like I am doing in the example below).
If it's ok to dynamically change the font of the Text widget with the click of a button, then the following could be a simple solution that uses a Toplevel widget to let the user write the font and size:
import Tkinter as tk
def choose_font():
global m, text # I hate to use global, but for simplicity
t = tk.Toplevel(m)
font_name = tk.Label(t, text='Font Name: ')
font_name.grid(row=0, column=0, sticky='nsew')
enter_font = tk.Entry(t)
enter_font.grid(row=0, column=1, sticky='nsew')
font_size = tk.Label(t, text='Font Size: ')
font_size.grid(row=1, column=0, sticky='nsew')
enter_size = tk.Entry(t)
enter_size.grid(row=1, column=1, sticky='nsew')
# associating a lambda with the call to text.config()
# to change the font of text (a Text widget reference)
ok_btn = tk.Button(t, text='Apply Changes',
command=lambda: text.config(font=(enter_font.get(),
enter_size.get())))
ok_btn.grid(row=2, column=1, sticky='nsew')
# just to make strechable widgets
# you don't strictly need this
for i in range(2):
t.grid_rowconfigure(i, weight=1)
t.grid_columnconfigure(i, weight=1)
t.grid_rowconfigure(2, weight=1)
m = tk.Tk()
text = tk.Text(m)
text.pack(expand=1, fill='both')
chooser = tk.Button(m, text='Choose Font', command=choose_font)
chooser.pack(side='bottom')
tk.mainloop()
When you click Choose Font, another window shows up, where you can insert the font name and the font size. You can apply the new font name and font size through the click of another Button Apply Changes, which uses a lambda.
Note that I have not handled any possible wrong inputs (for example inserting a letter for the size), you can do it by your own.
The problem is how you are specifying the font. You should use a tuple rather than a string. Try this:
font = (fontname, size)
textPad.config(
...,
font=font,
...
)
A good place for tkinter documentation is effbot.org. On the page about widget styling it says this about specifying the font:
Note that if the family name contains spaces, you must use the tuple
syntax described above.

Tabbed GUI keeps hanging on entry box

I have a very primitive GUI built with Tkinter. This is my first attempt at a GUI so I am struggling to understand what is going on (and with syntax). Here is what I have:
from __future__ import division, print_function
import os, ttk, tkFileDialog, Tkconstants
import Tkinter as tk
import datetime as dt
Tkinter = tk
# define OS version
version = '0.0.2'
class TestGUI(tk.Tk):
def __init__(self,parent):
tk.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
# try building list of instruments and sites
if os.path.isfile('config'):
with open(''config','r') as config:
config = dict( [(r.split('=')[0].strip(), r.split('=')[1].strip()) for r in config.read().split('\n') if r[0]<>'#'] )
self.datapath = config['datapath']
else:
self.datapath = '../'
def initialize(self):
self.grid()
# set up tabs
self.geometry( "%dx%d+%d+%d" % (1500, 900, 200, 50) )
nb = ttk.Notebook(self)
nb.pack(fill='both',expand='yes')
f1 = tk.Frame(bg='green')
f2 = tk.Frame(bg='blue')
f3 = tk.Frame(bg='red')
f1.grid()
f2.grid()
f3.grid()
nb.add(f1, text='General'.ljust(12,' '))
nb.add(f2, text='Plot'.ljust(12,' '))
nb.add(f3, text='Analysis'.ljust(12,' '))
button = tk.Button(f2,text='I AM A BUTTON!')
button.pack(side='left', anchor='nw', padx=3, pady=5)
# insert button and text box for specifying data location
path_button = tk.Button(f1,text='Browse',command=self.askdirectory).pack(side='left', anchor='nw', padx=10, pady=15)
self.path_entry = tk.StringVar()
self.entry = tk.Entry(f1,textvariable=self.path_entry)
self.entry.grid(column=12,row=8,columnspan=10)
self.entry.bind("<Return>", self.OnPressEnter)
self.path_entry.set(u"Sites directory path...")
def OnButtonClick(self):
print("You clicked the button !")
def OnPressEnter(self,event):
print("You pressed enter !")
def askdirectory(self):
"""Returns a selected directoryname."""
self.datapath = tkFileDialog.askdirectory()
self.path_entry.set(self.datapath)
if __name__ == "__main__":
app = TestGUI(None)
app.title(version)
app.mainloop()
My problem is centered around the addition of an entry box here:
self.path_entry = tk.StringVar()
self.entry = tk.Entry(f1,textvariable=self.path_entry)
self.entry.grid(column=12,row=8,columnspan=10)
self.entry.bind("<Return>", self.OnPressEnter)
self.path_entry.set(u"Sites directory path...")
If I run the code as-is, it just hangs (it also hangs if I use "f2"; I suspect it is getting caught in the infinite loop without actually doing anything). However, if I change the parent from "f1" to "f3" or it works (the entry box is now in frame 3 instead of frame 1, but it at least does not hang on me). There is another issue even when f3 is used: the entry box's width/position never change despite my changing of column/row/columnspan values.
Does anyone know why the code is hanging when I specify "f1" or "f2" and how to fix it?
Does anyone know why my entry box position/size is not changing?
You have put widgets in f1 and f2 using the pack geometry manager:
button = tk.Button(f2,text='I AM A BUTTON!')
button.pack(side='left', anchor='nw', padx=3, pady=5)
#and
path_button = tk.Button(f1,text='Browse',command=self.askdirectory).pack(side='left', anchor='nw', padx=10, pady=15)
Mixing geometry managers can lead to your program hanging, so using grid to put in the Entry does exactly that.
From effbot.org:
Warning: Never mix grid and pack in the same master window. Tkinter will happily spend the rest of your lifetime trying to negotiate a solution that both managers are happy with. Instead of waiting, kill the application, and take another look at your code. A common mistake is to use the wrong parent for some of the widgets.
The problem you describe of the Entry not changing position is because it is the only widget there, so the row(s) and column(s) in which the entry is are the only ones which do not have a width and height of 0. To make rows and columns without widgets take up space, use grid_rowconfigure(index, weight=x) where x is non-zero. An example is given in this answer.
Again from effbot.org:
weight=
A relative weight used to distribute additional space between rows. A row with the weight 2 will grow twice as fast as a row with weight 1. The default is 0, which means that the row will not grow at all.

Getting the text of label once button is clicked (Tkinter)

I am new to Python and Tkinter so I am trying to create a sample program to explore.
The program basically shows the names as a Label then 4 buttons will be put right next to the Label.
One of the buttons is "Delete" and what I want to do is, the button will get the name of the Label that is right next to that 'Delete" button.
The code is :
from Tkinter import *
class GUI():
def __init__(self):
self.namelist = ["Mark","Anna","Jason","Lenna",
"Leo","Zucharich","Robinson",
"AReallyLongNameThatMightExist"]
self.canvas = Canvas(width=1200,height=700)
self.canvas.pack(expand=YES,fill=BOTH)
def Friends(self):
frame = Frame(self.canvas)
frame.place(x=600,y=300)
#Frame for showing names of friends
row = 0
for x in self.namelist:
label = Label(frame,text="%s "%x)
chatButton = Button(frame,text="Chat")
delButton = Button(frame,text="Delete")
setcloseButton = Button(frame,text="Set Close")
setgroupButton = Button(frame,text="Set Group")
label.grid(row=row, column=0, sticky="W")
chatButton.grid(row=row, column=1)
delButton.grid(row=row, column=2)
setcloseButton.grid(row=row, column=3)
setgroupButton.grid(row=row, column=4)
row = row + 1
mainloop()
GUI = GUI()
GUI.Friends()
Example: If you run the code, then when you click "Delete" button next to "Mark", then the button will return "Mark".
Thanks!
Tk buttons have a command option to allow you to specify code to be run when the button is clicked. In this case you just want to pass the sibling widget name to your function. You can do this by capturing the widget name at creation time:
label = ...
delButton = Button(frame,text="Delete",
command=self.makeClosure(label))
...
def makeClosure(self, labelWidget):
return lambda: self.onClick(labelWidget)
def onClick(self, labelWidget):
print(labelWidget["text"])
In this example, when we create the delButton widget, the command is defined as a lambda that creates a closure including the label variable as it is defined at the time when this lambda is defined. Now when the delButton is clicked, this value will be passed to the onClick function which can use this to call methods on the widget at runtime.

Python PyQt/PySide QMdiArea subwindows scroll not working in TabbedView

I have setup simple example using PyQt designer.See below.
I have mdiarea in in which i am adding a form as subwindow. I made form a bit lengthier than mainwindow to see if scroll-bar appears for child sub-window.
PROBLEM:
If i set mdiarea to setViewMode(QtGui.QMdiArea.TabbedView) scrollbars stop working and disappear. Howeevr If i dont use TabbedView, scrollbars work fine.
Can anyone tell me whats wrong ? I need TabbedView of mdiarea with working scrollbars.
I am using Python 2.7,PyQT 4.8.4/PySide 1.2.1 on win7.
Python Sample Code:
Comment the line self.mdiArea.setViewMode to see example working.
import sys
from PyQt4 import QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName( "MainWindow" )
MainWindow.resize(500, 400)
self.centralwidget = QtGui.QWidget(MainWindow)
self.centralwidget.setObjectName( "centralwidget" )
self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName( "verticalLayout" )
self.mdiArea = QtGui.QMdiArea(self.centralwidget)
self.mdiArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.mdiArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
self.mdiArea.setActivationOrder(QtGui.QMdiArea.CreationOrder)
self.mdiArea.setViewMode(QtGui.QMdiArea.TabbedView)
self.mdiArea.setTabsClosable(True)
self.mdiArea.setTabsMovable(True)
self.mdiArea.setObjectName( "mdiArea" )
self.verticalLayout.addWidget(self.mdiArea)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtGui.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 508, 21))
self.menubar.setObjectName( "menubar" )
self.menuAdd = QtGui.QMenu(self.menubar)
self.menuAdd.setObjectName( "menuAdd" )
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtGui.QStatusBar(MainWindow)
self.statusbar.setObjectName( "statusbar" )
MainWindow.setStatusBar(self.statusbar)
self.menubar.addAction(self.menuAdd.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle( "MainWindow" )
self.menuAdd.setTitle( "&Add Form" )
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName( ("Form"))
Form.resize(400, 800)
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setObjectName( ("gridLayout"))
self.plainTextEdit = QtGui.QPlainTextEdit(Form)
self.plainTextEdit.setMinimumSize(QtCore.QSize(0, 731))
self.plainTextEdit.setObjectName( ("plainTextEdit"))
self.gridLayout.addWidget(self.plainTextEdit, 0, 0, 1, 1)
self.buttonBox = QtGui.QDialogButtonBox(Form)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName( ("buttonBox"))
self.gridLayout.addWidget(self.buttonBox, 1, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle( "Lengthy subwindow" )
self.plainTextEdit.setPlainText( "Lengthy Form" )
class MyApp(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyApp, self).__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
def Add_Subwindow(self):
widget = QtGui.QWidget()
self.subwin_abq = Ui_Form()
self.subwin_abq.setupUi(widget)
self.subwindow = QtGui.QMdiSubWindow(self.ui.mdiArea)
widget.setParent(self.subwindow)
self.subwindow.setWidget(widget)
self.subwindow.setWindowTitle("testing")
self.ui.mdiArea.addSubWindow(self.subwindow)
widget.show()
self.subwindow.show()
self.subwindow.widget().show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
window = MyApp()
window.show()
window.Add_Subwindow()
sys.exit(app.exec_())
Just wanted to say thanks for the code in OP - was looking for a simple MDI example in PyQT, and yours helped I lot! I don't exactly have an answer, but this is what I can note so far: I have Python 2.7,PyQT 4.8.3, and just with commenting the setTabsClosable and setTabsMovable line, I could get your example to show like this:
I downloaded designer-qt4 and looked there about QMdiArea, there seems to be nothing called TabbedView. So I found this:
QtWidgets 5.0: QMdiArea Class | Documentation | Qt Project
enum ViewMode { SubWindowView, TabbedView }
This enum describes the view mode of the area; i.e. how sub-windows will be displayed.
SubWindowView 0 Display sub-windows with window frames (default).
TabbedView 1 Display sub-windows with tabs in a tab bar.
documentMode: This property holds whether the tab bar is set to document mode in tabbed view mode.
The way I read this: either you get to display subwindows in MDI fashion (so they can be larger than the window, with scrollbars) or the subwindows become tabs in tabbed view - and there the size of the subwindow doesn't matter anymore, so it expands to take up the available tabbed area. Also, in your code, self.ui.mdiArea.documentMode() returns False in both cases.
I also added this snippet at end of your MyApp.Add_Subwindow():
sp = self.subwindow.sizePolicy()
print sp.__dict__
#print dir(sp)
for attr in dir(sp):
try:
print "obj.%s = %s" % (attr, getattr(sp, attr))
except: pass
This dumps some interesting data (I'm not sure if those are object properties, though):
obj.ButtonBox = 2
obj.CheckBox = 4
obj.ComboBox = 8
obj.ControlType = <class 'PyQt4.QtGui.ControlType'>
obj.ControlTypes = <class 'PyQt4.QtGui.ControlTypes'>
obj.DefaultType = 1
obj.ExpandFlag = 2
obj.Expanding = 7
obj.Fixed = 0
obj.Frame = 16
...
... but also these don't change in running tabbed vs. MDI mode.
So, maybe this is the intended behavior? If that is so, that would mean you'd have to find something like a "lone" tab display widget; add programmatically several QMdiAreas; hide all of them but the default one at start; and then bind a click on respective tabs to show "their" QMdiArea and hide the others (but needless to say, I haven't tested it).