Canvas on frames & Switching between frames using buttons - python

I am a newbie to python and Tkinter, please mind my silly mistakes if any.
The code I am attaching is a generalised and simpler version in order to get and test simply. Once I am ok with it, will prepare the application code.
I have two frames, who have their parent as the root geometry window.
Each frame has many canvases drawn in my main application, but I am drawing only one sample rectangle in my question for the sake of making it short.
My problem is while I draw two canvas on two different frames, on running the program, both appear simultaneously.
import tkinter as tk
from tkinter import ttk
from tkinter import font
from tkinter import *
root=tk.Tk()
root.geometry("550x550")
Crel='groove'
Cbw=3
h=50
w=50
#####Frame 1 & rectangle Canvas drawn########
Cparent=ttk.Frame(root,height=200,width=200)
Cparent.pack()
hallname=tk.Canvas(Cparent,height=h,width=w,relief=str(Crel),
borderwidth=int(Cbw))
hallname.place(x=150,y=150)
#####Frame 2 & rectangle Canvas drawn########
Cparent2=ttk.Frame(root,height=200,width=200)
Cparent2.pack()
hallname1=tk.Canvas(Cparent2,height=h,width=w,relief=str(Crel),
borderwidth=int(Cbw))
hallname1.place(x=30,y=30)
#####Function to switch frames########
def pushbut(obj):
obj.tkraise(obj)
#####Buttons size and font#######
buttonnamefont=font.Font(root,family="Helvetica",size=10,weight="bold")
Details=Button(root,text='Details',font=buttonnamefont,
command=lambda:pushbut(Cparent))
Overview=Button(root,text='Overview',font=buttonnamefont,
command=lambda:pushbut(Cparent2))
Overview.place(x=300,y=520)
Details.place(x=100,y=520)
Cparent.tkraise()
root.update()
If i try to show one frame using tkraise function, still the other frame also shows up.
About switching frames, I have made two buttons,and tried to switch between frames using lamba function, however failed to do so.
Please let me know for minute and idiotic mistakes if made by me;)

Related

Real Time Data with tkinter

I am looking for a simple way to display changing real time data in a GUI in python. I am connected to 2 devices and want to display data constantly (like 20 different values), and when I press a button I want to control the one device.
Unfortunately I fail already with the display of the data. For this I have looked at some tkinter tutorials and explanations.
My idea was to implement it with a config function and to overwrite the label continuously. As example how I wanted to display one value:
import tkinter as tk
from pydualsense import pydualsense
# connect to the device
dualsense = pydualsense()
dualsense.init()
# create a window
window = tk.Tk()
# function for updating data
def show_data():
global dualsense
data_label_output.config(text=dualsense.state.LX)
# showing the data as a lable
data_label_output = tk.Label(window)
data_label_output.grid(row=1, column=1)
show_data()
#### or different solution
# showing the data as a lable
data_label_output = tk.Label(window, comand=show_data)
data_label_output.grid(row=1, column=1)
window.mainloop()
Unfortunately, the value is displayed only once at the beginning and nothing changes after that.
Another problem:
When I press the button, I want to be able to control the one device. For this I have a while True loop that permanently checks if a button is pressed and then executes actions. As a separate program no problem, but how do I integrate this into the tkinter GUI? When I start this PyCharm always crashes.
I use PyCharm and Python 3.8
About simple and functional ideas I would be happy, also to other tools/modules etc., as long as you can easily and quickly implement the idea. It's only for a research project and the programming is only a means to an end.
You can use the after method in tkinter to run something after a short delay. The following code will run show_data once the GUI is ready and then again every 1000 milliseconds.
import tkinter as tk
from pydualsense import pydualsense
# connect to the device
dualsense = pydualsense()
dualsense.init()
# create a window
window = tk.Tk()
# function for updating data
def show_data():
global dualsense
data_label_output.config(text=dualsense.state.LX)
window.after(1000,show_data)
# showing the data as a lable
data_label_output = tk.Label(window)
data_label_output.grid(row=1, column=1)
window.after_idle(show_data)
window.mainloop()
This resolves the updating issue, I'm not sure what behaviour you want when you press the button but if you elaborate and explain, I might be able to help and update this answer.

Tkinter Label doesn't work as I thought it does [duplicate]

This question already has an answer here:
When should I use root.update() in tkInter for python
(1 answer)
Closed 1 year ago.
Beginner programmer here currently trying to learn Tkinter for a school assignment.
I have a GUI class that stores the Tkinter labels etc, the labels are innitiated like this:
# GUI for Player 1
self.player_1_name_field = Label(
self.root,
text="Player 1",
font=GUI_Settings.player_information_font,
anchor=W,
background=GUI_Settings.playerfield_active_color
)
I then create a Game() object that looks like this:
class Game():
def __init__(self):
self.GUI = GUI()
self.GUI.initializeBoard()
self.GUI.root.mainloop()
When I run the code, the labels do get created and are where they are supposed to be, but are completely black. Once I move or resize the window it instantly becomes how I want it to be, it just behaves weird when at the start of the code
The interesting thing is that I also have a Canvas and a List that work perfectly fine, only the Labels are not cooperative
If you need further info, just ask for it!
Thank you!
Edit 1: I have a function called drawWindow() that redraws the chessboard when I re-configure the window. In the init of the GUI class I set self.root.bind("<Configure>", self.drawWindow). If I remove that line of code, the Labels work but the Canvas doesn't anymore. I'm so confused. For anyone wanting to take a look at my tiny code: https://codeshare.io/DZYzyZ
See comment of Thingamabobs
The issue is self.root.update(). Remove this line and you'll be fine.
When should I use root.update() in tkInter for python.
This works but you shouldn't do it
This is a tricky issue. Your problem come from the bind of the configure event. Bind to the root window, it is applied to all sub-widgets of the window, which cause the bug (I don't know why yet).
This will solve your issue (line 202):
self.chessboard.bind("<Configure>", self.drawWindow)
instead of:
self.root.bind("<Configure>", self.drawWindow)
Result without moving or resizing the window:
I found the information here (french forum).

tkinter putting widgets into frames [duplicate]

This question already has answers here:
Tkinter Frame container color not visible
(2 answers)
Closed 4 years ago.
I feel like I am missing something very basic here. This is my first try creating a GUI in Python. I try to add several frames inside my main window and place stuff inside by using grid manager. The frame creation and sizing and stuff works fine, until I add anything inside the frame. Like in this example with only one frame, when I put my dummy label, the frame just completely vanishes and only the label is displayed.
I really want to understand what is going on and why it is behaving like it is ... and of course, how to fix it. Thanks a lot.
from tkinter import *
window = Tk()
# Window geometry
window.title("Tk")
window.geometry('850x600')
# Set Frames
LeftTopFrame = Frame(window,bg='red',height=200,width=300)
LeftTopFrame.pack(fill=X,side=LEFT)
lblInp = Label(LeftTopFrame, text='Label',font=('Tahoma', 10))
lblInp.grid(column=0,row=0)
window.mainloop()
Tkinter frames shrink or grow to fit their contents. Use
LeftTopFrame.grid_propagate(0)

tkinter: Can't make frame scrollable

On python tkinter, I am using 2 different frames on a Toplevel window, one on the right and another on the left.
The frame which is on right side is not scrollable. I have created a canvas on top of the frame on that frame and one more frame on top of that canvas. I have made that canvas scrollable and pasted the widgets on that canvas but it's not scrollable. I am attaching the code of the scrollable part.
w1 = Canvas(frame2, width=600, height=300,background="white", scrollregion=(1500,1500,3000,3000))
scr_h1 = ttk.Scrollbar(frame2,orient=HORIZONTAL)
scr_h1.pack(side=BOTTOM,fill=X)
scr_h1.config(command=w1.xview)
scr_v1 = ttk.Scrollbar(frame2,orient=VERTICAL)
scr_v1.pack(side=RIGHT,fill=Y)
scr_v1.config(command=w1.yview)
w1.config(xscrollcommand=scr_h1.set,yscrollcommand=scr_v1.set)
w1.pack(fill=BOTH,expand=True)
This code works for me running Python 3.4 - a tkinter window pops up with a red oval (for testing), and the scrollbar allows you to navigate the frame. If you are using Python 2, change tkinter to Tkinter (capital T).
from tkinter import *
root = Tk()
frame2 = Frame(root)
frame2.pack(side=RIGHT)
w1 = Canvas(frame2, width=600, height=300,background="white", scrollregion=(0,0,3000,3000))
scr_h1 = Scrollbar(frame2,orient=HORIZONTAL)
scr_h1.pack(side=BOTTOM,fill=X)
scr_h1.config(command=w1.xview)
scr_v1 = Scrollbar(frame2,orient=VERTICAL)
scr_v1.pack(side=RIGHT,fill=Y)
scr_v1.config(command=w1.yview)
w1.config(xscrollcommand=scr_h1.set,yscrollcommand=scr_v1.set)
w1.pack(fill=BOTH,expand=True)
# inserted to see if it's actually scrolling
w1.create_oval(0,0,50,50,fill='red')
root.mainloop()
Two Possible Issues
Why were you using a ttk ScrollBar? The simple tkinter scroll bar will suffice for your code. When things aren't working, it might help to go back to the simpler model.
Why your starting scroll region was 1500 - any object placed on the canvas in the first 1500 units in either direction were not visible, with this setting, which may have given you the illusion that the scrollbar was not working. See http://effbot.org/zone/tkinter-scrollbar-patterns.htm for more information on using scroll bars.
It should not matter that there are two frames or their orientation, though you may run into problems if you try to mix managers (grid,pack,etc.). These problems are more along the lines of stalled programs, not stationary scrollbars.

tkinter's .pack_propagate() method

I am experimenting with Tkinter, as I was trying to figure out is there a way to set the tkinter's window size without using canvas. I came upon this how to set frame size question on SO's Question & Answer. So I went ahead and test it by writing a very small program to display a text label. But I found out it is "missing", or disappear when I use frame.pack_propagate(0)
import tkinter as tk
root = tk.Tk()
frame = tk.Frame(root, width=400, height=400)
# Does not work at the moment, textBox is missing
# frame.pack_propagate(0)
frame.pack()
textBox = tk.Label(frame, text="(x,y): ")
textBox.pack()
root.mainloop()
So my question is, can you explain why my textBox (Label) is not appearing when I use the frame.pack_propagate(0) instead of frame.pack() method? And secondly, is there a way to set the window size without using a canvas? I want to know because I am writing a series of small programs to teach my friend about tkinter, before introducing canvas to him. It would be nice if the window size are all the same across my tkinter samples. And I am just wondering as well (curious). Thank you very much.
I am using python 3.2.2 on MAC OS 10.5.8.
pack_propagate only sets a flag, it doesn't cause the frame to be placed in the widget. It is not a substitute for calling pack.
In other words you must do this:
# put the frame in its parent
frame.pack()
# tell frame not to let its children control its size
frame.pack_propagate(0)
# put the textbox in the frame
textBox.pack()
To answer your second question: Yeah, there is a way.
tkinters Tk do have the Tk.geometry function. When you just call it without arguments, you will get the current geometry in form of 'widthxheight+x+y', so for example (on Windows 10) '200x200+26+26' when you create your first Tk window. Using that format you can resize the Tk by, e.g., writing: root.geometry('400x500+60+60') to set the width to 400, the height to 500 and place it at the coordinates (60|60).
This works for Tk alswell as for Toplevel. But Toplevel also takes the arguments height and width when initialized or configured. If you want them to keep their size when packing something inside just use root.pack_propagate(False) on them.
By the way there is something similar for the grid manager: root.grid_propagate(False)

Categories

Resources