Professional Documents
Culture Documents
Designing Tkinter Forms With Page (CAS)
Designing Tkinter Forms With Page (CAS)
If you are familiar with designing forms for Visual Basic and C# using Visual Studio, or even Eclipse
FormsBuilder for Java, you will appreciate the convenience of these IDE development tools.
When it comes to Python GUIs then it becomes a whole different ballgame. There are a number of
GUI designers but they all have one major problem, which is they require different libraries that
need to be installed to use them and run the code afterwards.
This is OK at home, but what about at a school, where you do not have priveleges to install these
libraries? Usually the only GUI there is Tkinter, as it is part of the original Python distribution.
Luckily there is a solution, which does not need anything to be ‘installed’ ie registry entries, .dll files
in System32, desktop icons etc. etc. It runs from a USB drive, or any location where you can run .exe
executable files. This often includes your Documents user space!
4) If you want to use SharpDevelop to create your own Page/Tcl launcher in C# for use in the
PortableApps distribution, and to test the comparisons detailed below go to:
http://www.icsharpcode.net/OpenSource/SD/Default.aspx This is a 50MB application and
runs from any location, including USB
The documentation and tutorial links above are helpful, but for a quick guide to setting up and use
read on:
Page 1 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
‘Install’ ActiveTcl by double-clicking the executable file:
Ignore the text again, click the ‘Accept’ radio button and click ‘Next’
You cannot change any options here except the path, so leave it at C:\Tcl (as it is going to be moved
later anyway), unless on a school system, when you should use choose the root of your documents
folder (usually U:\ or N:\ which represent mapped drive letters to your Documents share on the
server)
Click ‘Next’
Page 2 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Click ‘Next’. Click ‘Next’ again You may get errors at school due to not being able to modify the start
menu
All Done. The highlighted text informs you the only way to un-install is through the uninstall entry
added to the start menu. Nonsense: Select the folder and press the Delete key… (Only if you want to
‘uninstall’ it!)
Hit ‘Finish’
Click ‘Yes’
A full-window installer emerges with only the option for changing the path.
Leave it at C:\page unless on a school system then use the root of your Documents, similar to Tcl
above.
Again there may be errors due to shortcut and start menu creation on school systems.
Once completed drag’n’drop the Tcl folder into the page folder. The complete page folder should
contain the following:
Page 3 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
If you managed to get a desktop icon for page. The properties page for this icon (right-click
properties) show the following Target:
C:\page\winpage.bat
This time a bunch of separate dialogs will open at the corners of the screen.
As all absolute pathnames have been removed, this will now work wherever you move the page
folder.
Copy the page folder to a usb or any convenient location and you can run it directly from there.
Page 4 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Adding Page to the PortableApps distribution
If you drop the page folder into the PortableApps folder, it will not show up in the menu, as there is
no associated .exe file with a suitable icon.
You have to make your own using C# in either SharpDevelop or Visual Studio.
Use the icon located in \page\WIN_INSTALL as the project icon and use the following code in
Program.cs:
using System;
using System.Linq;
using System.IO;
using System.Threading;
namespace PageLauncher
{
class Program
{
public static void Main(string[] args)
{
// Make sure the source code of this development is located within the \page folder
// else paths/files will not be found!
Console.WriteLine("C# Launcher for Page");
string driveLetter = Path.GetPathRoot(Environment.CurrentDirectory); // X:\
Console.WriteLine("Running from drive: " + driveLetter);
/* full startup of .exe eg in \bin folder
possible locations:
X:\PortableApps\page\PageLauncher.exe
X:\PortableApps\page\PageLauncher\PageLauncher\bin\Debug\PageLauncher.exe
X:\page\PageLauncher.exe
*/
string AppPath =
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Page 5 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Console.WriteLine("PageLauncher.exe (C# launcher) located at:\n\t" + AppPath +
@"\PageLauncher.exe");
string PagePath = AppPath.Substring(0, AppPath.IndexOf(@"\page")) + @"\page";
string TclPath = PagePath + @"\Tcl";
if(Directory.Exists(TclPath))
{
Console.WriteLine("Wish.exe (executable) located at:\n\t" + TclPath +
@"\bin\wish.exe");
Console.WriteLine("\nLaunching Page\n\nHold tight!");
try
{
//Mimic batch file contents: start /min Tcl\bin\wish.exe page.tcl %1
System.Diagnostics.Process startPage = new System.Diagnostics.Process();
startPage.StartInfo.FileName = TclPath + @"\bin\wish.exe";
startPage.StartInfo.Arguments = PagePath + @"\page.tcl";
startPage.Start();
Console.WriteLine("\nClosing in 10 seconds...");
Thread.Sleep(10000);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
else
{
Console.WriteLine("Cannot find directory " + TclPath);
Console.WriteLine("Install or copy TCL into page directory");
Console.WriteLine("Available from: http://www.activestate.com/activetcl/downloads");
Console.WriteLine("Press enter to exit");
Console.ReadLine();
}
}
}
}
Copy the compiled .exe from the \bin folder to the root of the \page folder.
Page 6 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Comparison of the use of Page for those familiar with Visual Studio and Java Forms
Builder
C#
Take an example of a simple form with a button, label and textbox:
This was made on the SharpDevelop IDE in a few minutes. (Launch from PortableApps)
- Add a label:
Name lblDemo
BorderStyle Fixed3D
Font Segoe UI, 8.25pt
Location 12,170
Size 270,30
Text Clicking the button will copy the textbox text here
TextAlign MiddleCenter
Page 7 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
This generates the designer code behind the scenes as follows:
Page 8 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Repeat using Eclipse WindowBuilder
Java
The same project created with the same properties takes a bit longer, but gives the following GUI
designer code (The declarations have been moved out of ‘ initialise()’ so they can be accessed from
outside the function. Highlighted lines have been added or modified):
lblDemo = new JLabel("Clicking the button will copy the textbox text here");
lblDemo.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
lblDemo.setHorizontalTextPosition(SwingConstants.CENTER);
lblDemo.setHorizontalAlignment(SwingConstants.CENTER);
lblDemo.setBounds(12, 170, 270, 30);
frame.getContentPane().add(lblDemo);
The main difference here is the events for the button Click in C# are declared in the designer, but
coded in the MainForm source file, to encourage programmers NOT to alter the design code.
In Java it is all thrown together and left to the programmer to create new classes or functions to
handle the event code. The line lblDemo.setText(txtDemo.getText()); is written directly into the event
Page 9 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
handler. You can of course write a new function to do this, and call the function in the event handler
instead. The equivalent line lblDemo.Text = txtDemo.Text; in C# is found in the separate source file
Program.cs:
using System;
using System.Windows.Forms;
namespace Cross_Platform_Demo
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.CenterToScreen();
}
void BtnDemoClick(object sender, EventArgs e)
{
lblDemo.Text = txtDemo.Text;
}
}
}
Python/Tkinter
Start Page and click the Toplevel icon in the Widget Toolbar:
Go back to the Widget Toolbar and Click on the Themed widgets Tbutton icon
Click inside your new window, now resized and re-titled. The button will be drawn.
Page 10 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Alias btnDemo
command btnDemoClick
text Click Me!
Geometry: x position 70
Geometry: y position 35
Geometry:width 150
Geometry:height 40
Go back to the Widget Toolbar and Click on the Themed widgets TEntry icon (The Tkinter designers
obviously did not think of using TextBox as a name used since the invention of Visual basic in the
1980s)
Alias txtDemo
font Segoe UI 10
Geometry: x position 12
Geometry: y position 100
Geometry:width 270
Geometry:height 30
Page 11 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Go back to the Widget Toolbar and Click on the Themed widgets TLabel icon
Alias lblDemo
Anchor center
relief sunken
text Clicking the button will copy the
textbox text here
Geometry: x position 12
Geometry: y position 170
Geometry:width 270
Geometry:height 30
This will also open a file selector dialog prompting you to save the project.
Page 12 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
Choose an appropriate folder and filename to save the design in .tcl format. (I used demo as the
filename)
The Python file will open with the same name as the .tcl file you just saved. (demo.py)
#! /usr/bin/env python
#
# GUI module generated by PAGE version 4.8.6
# In conjunction with Tcl version 8.6
# Jan 14, 2017 07:33:42 PM
import sys
The above code is not required and can be deleted
try:
from Tkinter import *
except ImportError:
from tkinter import *
try:
import ttk
py3 = 0
except ImportError:
import tkinter.ttk as ttk
py3 = 1
The above code checks which version of Python you are using. Assuming you are on Python 3 this
can be changed to:
The next statement imports the second Python file created by Page:
import demo_support
The following three functions are used when starting from the support module:
def vp_start_gui():
'''Starting point when module is the main routine.'''
global val, w, root
root = Tk()
top = Cross_Platfom_Demo (root)
demo_support.init(root, top)
root.mainloop()
w = None
def create_Cross_Platfom_Demo(root, *args, **kwargs):
'''Starting point when module is imported by another program.'''
global w, w_win, rt
rt = root
w = Toplevel (root)
top = Cross_Platfom_Demo (w)
demo_support.init(w, top, *args, **kwargs)
return (w, top)
def destroy_Cross_Platfom_Demo():
global w
w.destroy()
w = None
Page 13 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
The above lines can be deleted, as the Demo project will always start from the main module.
The class below is the impotrant bit:
class Cross_Platfom_Demo:
def __init__(self, top=None):
'''This class configures and populates the toplevel window.
top is the toplevel containing window.'''
self._bgcolor = '#d9d9d9' # X11 color: 'gray85'
self._fgcolor = '#000000' # X11 color: 'black'
self._compcolor = '#d9d9d9' # X11 color: 'gray85'
self._ana1color = '#d9d9d9' # X11 color: 'gray85'
self._ana2color = '#d9d9d9' # X11 color: 'gray85'
self.font3 = "-family {Segoe UI} -size 10 -weight normal -slant roman -underline 0 -overstrike
0"
self.style = ttk.Style()
if sys.platform == "win32":
self.style.theme_use('winnative')
self.style.configure('.',background=self._bgcolor)
self.style.configure('.',foreground=self._fgcolor)
self.style.configure('.',font="TkDefaultFont")
self.style.map('.',background=[('selected', self._compcolor), ('active',self._ana2color)])
top.geometry("300x270+0+0")
top.title("Cross Platfom Demo")
top.configure(background="#d9d9d9")
top.configure(highlightbackground="#d9d9d9")
top.configure(highlightcolor="black")
self.btnDemo = ttk.Button(top)
self.btnDemo.place(relx=0.23, rely=0.12, height=40, width=150)
self.btnDemo.configure(command=demo_support.btnDemoClick)
self.btnDemo.configure(takefocus="")
self.btnDemo.configure(text='''Click Me!''')
self.txtDemo = ttk.Entry(top)
self.txtDemo.place(relx=0.03, rely=0.33, relheight=0.1, relwidth=0.9)
self.txtDemo.configure(font=self.font3)
self.txtDemo.configure(takefocus="")
self.txtDemo.configure(cursor="ibeam")
self.lblDemo = ttk.Label(top)
self.lblDemo.place(relx=0.03, rely=0.57, height=30, width=270)
self.lblDemo.configure(background="#d9d9d9")
self.lblDemo.configure(foreground="#000000")
self.lblDemo.configure(relief=SUNKEN)
self.lblDemo.configure(anchor=CENTER)
self.lblDemo.configure(text='''Clicking the button will copy the textbox text here''')
The code below is used to check if the script is launched from this module, then runs the function
above: vp_start_gui()
if __name__ == '__main__':
vp_start_gui()
At first, using the two scripts seems to run along the same lines as the C# version, with the GUI
design in one, and the events in the other, but it does not work well when trying to fill the label with
the contents of the textbox, as you are constantly cross-referencing the two modules.
It makes much more sense to keep all the code used in the GUI design class, including events, similar
to the Java equivalent used earlier
Page 14 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
To make this script work change the Demo.py script:
1) Move the text in the function vp_start_gui() to the bottom of the script and delete the
function definition and the call to it after if __name__ == '__main__':
2) Delete everything above the class declaration except the top two lines highlighted
3) Modify self.btnDemo.configure() as highlighted
4) Add the function def btnDemoClick() as highlighted below (It can be cut from the
Demo_support.py file and modified)
class Cross_Platfom_Demo:
def __init__(self, top=None):
'''This class configures and populates the toplevel window.
top is the toplevel containing window.'''
self._bgcolor = '#d9d9d9' # X11 color: 'gray85'
self._fgcolor = '#000000' # X11 color: 'black'
self._compcolor = '#d9d9d9' # X11 color: 'gray85'
self._ana1color = '#d9d9d9' # X11 color: 'gray85'
self._ana2color = '#d9d9d9' # X11 color: 'gray85'
self.font3 = "-family {Segoe UI} -size 10 -weight normal -slant roman -underline 0 -overstrike
0"
self.style = ttk.Style()
if sys.platform == "win32":
self.style.theme_use('winnative')
self.style.configure('.',background=self._bgcolor)
self.style.configure('.',foreground=self._fgcolor)
self.style.configure('.',font="TkDefaultFont")
self.style.map('.',background=[('selected', self._compcolor), ('active',self._ana2color)])
top.geometry("300x270+0+0")
top.title("Cross Platfom Demo")
top.configure(background="#d9d9d9")
top.configure(highlightbackground="#d9d9d9")
top.configure(highlightcolor="black")
self.btnDemo = ttk.Button(top)
self.btnDemo.place(relx=0.23, rely=0.12, height=40, width=150)
self.btnDemo.configure(command=self.btnDemoClick)
self.btnDemo.configure(takefocus="")
self.btnDemo.configure(text='''Click Me!''')
self.txtDemo = ttk.Entry(top)
self.txtDemo.place(relx=0.03, rely=0.33, relheight=0.1, relwidth=0.9)
self.txtDemo.configure(font=self.font3)
self.txtDemo.configure(takefocus="")
self.txtDemo.configure(cursor="ibeam")
self.lblDemo = ttk.Label(top)
self.lblDemo.place(relx=0.03, rely=0.57, height=30, width=270)
self.lblDemo.configure(background="#d9d9d9")
self.lblDemo.configure(foreground="#000000")
self.lblDemo.configure(relief=SUNKEN)
self.lblDemo.configure(anchor=CENTER)
self.lblDemo.configure(text='''Clicking the button will copy the textbox text here''')
def btnDemoClick(self):
self.lblDemo.configure(text=self.txtDemo.get())
if __name__ == '__main__':
global root
root = Tk()
top = Cross_Platfom_Demo(root)
root.mainloop()
Page 15 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/
The Demo_support.py file can now be deleted. You now have a skeleton design, ready for filling in
the class with additional methods to handle the widgets you place in the designer.
C# Java Tkinter
The use of the Tkinter .place() method is close to the positioning methods used in C# and Java
WindowBuilder.
Page 16 of 16
This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
http://creativecommons.org/licenses/by-nc-sa/4.0/