I Want to place those two elements in different extremes of my window, so, the label will be placed on the left and the button in the right, as in the image below
I tried different styles of layout management, as pack and Grid, but cannot solve my problem.
main.py
from faces.schedules import Schedules
from faces.App import App
app = App()
schedules = Schedules(app)
app.mainloop()
Tkinter Window (app.py)
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.app_width = 800
self.app_height = 600
self.setup()
def setup(self):
self.title('Backup Manager')
self.iconbitmap('images/icon.ico')
#dimensoes
self.resizable(False, False)
self.geometry(newGeometry=f'{self.app_width}x{self.app_height}')
self.style = ttk.Style(self)
self.style.theme_use('xpnative')
Schedules.py
from tkinter.ttk import Button, Label, Frame
class Schedules(Frame):
def __init__(self, master):
super().__init__()
self.setupPage()
def setupPage(self):
self.header = Frame(self)
self.title = Label(self.header, text="Meus agendamentos")
self.setPageButton = Button(self.header, text='Mudar')
self.gridElements()
def gridElements(self):
self.header.grid(sticky='we')
self.title.grid(row=0, column=0, sticky='W')
self.setPageButton.grid(row=0, column=1, sticky= 'E')
self.grid()
I'd suggest using weighted columns with columnconfigure()
import tkinter as tk
root = tk.Tk()
root.geometry("200x200")
root.columnconfigure(1, weight = 2) # Configures column 1 to function as 2 columns
tk.Button(root, text = "Left") .grid(row = 0, column = 0)
tk.Button(root, text = "Right") .grid(row = 0, column = 1, sticky = tk.E)
root.mainloop()
For your case, I would suggest using .pack() instead of .grid():
main.py
from faces.schedules import Schedules
from faces.app import App
app = App()
schedules = Schedules(app)
schedules.pack(fill='x')
app.mainloop()
schedules.py
from tkinter.ttk import Button, Label, Frame
class Schedules(Frame):
def __init__(self, master):
super().__init__(master)
self.setupPage()
def setupPage(self):
self.header = Frame(self)
self.title = Label(self.header, text="Meus agendamentos")
self.setPageButton = Button(self.header, text='Mudar')
self.packElements()
def packElements(self):
# use pack() instead of grid()
self.header.pack(fill='x')
self.title.pack(side='left')
self.setPageButton.pack(side='right')
Have you tried manually placing it with .place? I use something like this:
self.setPageButton = Button(self.header, text="Meus agendamentos", command='What this button does if pressed').place(x = x-coord, y = y-coord) here
Since your app window is 800x600, you might want to try placing the button at (x = 780, y = 0 and moving it by experimentation. It's been a while since I've used tkinter, so not sure how well it might work.
Related
I'm trying to create an app with Tkinter which requires the user to hit the button of the first window and then a new window will appear where they'll write their name.
But i when i try to get the name, i always end up with an empty string.
Here's my code:
from tkinter import *
class first_class(object):
def __init__(self, window):
self.window = window
b1 = Button(window, text = "first_get", command = self.get_value_2)
b1.grid(row = 0, column = 1)
def get_value_2(self):
sc = Tk()
second_class(sc)
sc.mainloop()
class second_class(object):
def __init__(self, window):
def get_value_1():
print(self.name.get())
self.window = window
self.name = StringVar()
self.e1 = Entry(window, textvariable = self.name)
self.e1.grid(row = 0, column = 0)
b1 = Button(window, text = "second_get", command = get_value_1)
b1.grid(row = 0, column = 1)
window = Tk()
first_class(window)
window.mainloop()
What should i do to get the name properly?
Generally speaking, you should avoid calling Tk() more than once within a tkinter application. It's also hardly ever necessary to call mainloop() more than once.
Your code with the changes indicated below shows how to do this. Note that I also renamed and reformatted a few things so it follows the recommendations in PEP 8 - Style Guide for Python Code more closely — which I highly recommend you read and start following.
import tkinter as tk
class FirstClass(object):
def __init__(self, window):
self.window = window
b1 = tk.Button(window, text="first_get", command=self.get_value_2)
b1.grid(row=0, column=1)
def get_value_2(self):
# sc = tk.Tk() # REMOVED
SecondClass(self.window) # CHANGED
# sc.mainloop() # REMOVED
class SecondClass(object):
def __init__(self, window):
self.window = window
self.name = tk.StringVar()
self.e1 = tk.Entry(window, textvariable=self.name)
self.e1.grid(row=0, column=0)
def get_value_1():
print('self.name.get():', self.name.get())
b1 = tk.Button(window, text="second_get", command=get_value_1)
b1.grid(row=0, column=1)
window = tk.Tk()
FirstClass(window)
window.mainloop()
I am building a real time monitoring project where information is given in the first window and that's keep on updating in the second window. I am trying to monitor the updated information in parallel from a different window using the same code, but as I pressed the new button and given the new information it is updating in the previous window also but I wanted monitor window to be completely different, so that I can monitor the different information in parallel using the same code. Please have a look at the sample code and help me with the ideas.
The sample code:
import time
import threading
import tkinter.messagebox
from tkinter import ttk
import queue
from tkinter import *
class Demo1:
data=[]
def __init__(self, master):#Python scrollbar on text widget
self.master = master
self.t=tkinter.Text(self.master,height=20,width=50)
self.t.grid(row=1, column=1)
self.button = tkinter.Button(self.master,height=3,width=10, text="OK", command = self.new_window)
self.button.grid(row=2,column=1)
def new_window(self):
self.inputValue=self.t.get("1.0",'end-1c')
Demo1.data1=self.inputValue.split("\n")
self.master.destroy() # close the current window
self.master = tkinter.Toplevel() # create another Tk instance
self.app = Demo2(self.master) # create Demo2 window
self.master.mainloop()
class Demo2:
t1 = []
s1 = True
display = []
display1 = []
i=0
kas = True
num=0
j1=0
def __init__(self, master):
self.master = master
self.button = tkinter.Button(self.master,height=2,width=11, text="new",command=self.new).place(x=0,y=0)
self.label = tkinter.Label(self.master, text="monitor", font=("Arial",20)).grid(row=0, columnspan=3)
cols = ('aa','bb')
self.listBox = ttk.Treeview(self.master, columns=cols)
for col in cols:
self.listBox.heading(col, text=col)
self.listBox.column(col,minwidth=0,width=170)
self.listBox.grid(row=1, column=0)
self.a()
def a(self):
self._img=tkinter.PhotoImage(file="green1.gif")
a=Demo1.data1
for i,(a) in enumerate(a): #here I have some function which runs repeatedlly
self.listBox.insert('', 'end',image=self._img, value=(a))
threading.Timer(1.0, self.a).start()
def new(self):
main()
def main():
root = tkinter.Toplevel()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
I have given the pppp information to monitor but as a pressed new button and added the xx information its updating in the previous window also. Please help me with the idea so that the link between these window will be vanished.
Output:
You have some major issues with your program. Including how you are trying to use your classes. The Toplevel() object was giving me issue, so I used Tk(). This should show you how to properly use the classes with the window. Most importantly your second window needs to be created from global not the first window. Also Demo1.data is a reference to your class definition not the actual data you loaded. I hope this example is helpful.
from tkinter import *
# your second window should be created in global
def create_demo2():
global app, app2
root2 = Tk()
app2 = Demo2(root2, app)
class Demo1:
def __init__(self, window):
self.window = window
self.data = ""
self.button = Button(self.window, text="New Window",
command=create_demo2)
self.button.pack()
def set_data(self):
self.data = "data"
class Demo2:
# you could just use app from global scope, but I like to pass so that it is explicit.
def __init__(self, window, app1):
self.window = window
self.button_set = Button(self.window, text="Set", command=app1.set_data)
self.button_use = Button(self.window, text="Use", command=self.use_data)
self.app = app1
self.label = Label(self.window)
self.button_set.pack()
self.button_use.pack()
self.label.pack()
def use_data(self):
self.label.configure(text=self.app.data)
root = Tk()
app = Demo1(root)
app2 = None
root.mainloop()
I am new to python so I was trying to make a GUI, in that I have to place a button in a particular position.
I tried using self.nxt_form.place(x=200,y=100) instead of self.nxt_form.pack().
But the button disappeared and only the frame appeared when it ran. Can you tell me how to place the button in a particular position?
Here is the code:
import tkinter as tk
class Main_form:
def __init__(self, root,title="Simulated MTBF"):
self.root = root
self.frame = tk.Frame(self.root)
"""Button nxt_form which moves to next form"""
self.nxt_form = tk.Button(self.frame, text = 'Next Form', width = 25,command = self.new_window)
self.nxt_form.pack()
self.frame.pack()
"""command to open new window by clicking Button """
def new_window(self):
self.newWindow = tk.Toplevel(self.root)
self.app = Demo2(self.newWindow)
class Demo2:
def __init__(self, root):
self.root = root
self.frame = tk.Frame(self.root)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.root.destroy()
def main():
root = tk.Tk()
app = Main_form(root)
root.mainloop()
if __name__ == '__main__':
main()
when i am using tkinter i used column and row to position objects
self.btn = tk.Button(self, text = "button")
self.btn.grid(row = 1, column = 1)
EDIT - expanded on information in response to comment (below)
I would make an label and change its width and height to make the spacing you need (note im a beginer at python as well so this is probly a bad way but it works)
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.create_GUI()
def create_GUI(self):
frame1 = tk.LabelFrame(self, text="frame1", width=300, height=130, bd=5)
frame1.grid(row=0, column=0, columnspan=3, padx=8)
#the frame is not needed but it is a good thing to use as can group
#parts of your interface together
self.text1 = Entry(frame1)
#note if you were not using frames would just put self here
self.text1.grid(row = 1, column = 0)
self.text2 = Label(frame1, text = "",height = 10)
self.text2.grid(row = 2 , column = 0)
self.text3 = Entry(frame1)
self.text3.grid(row = 3, column = 0)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()
Also note that you can not use pack and grid together what you could do is group your objects in different frames then use grid in one frame and pack in a different frame. I personally prefer to use grid to pack as it gives you more control over your object then pack does
I am trying to create a program in tkinter which allows me to open an initial window then to keep it throughout all classes used. For example, if I was to create a button in a window then when I click this button, it would exuecute a method that destroys the widget, and then executes a new class that builds a new screen within the same window, such as text opposed to a button.
from tkinter import *
class Window1:
def __init__(self, master):
self.master = master
self.label = Button(self.master, text = "Example", command = self.load_new)
self.label.pack()
def load_new(self):
self.label.destroy()
## Code to execute next class
class Window2:
def __init__(self, master):
self.master = master
self.label = Label(self.master, text = "Example")
self.label.pack()
def main():
root = Tk()
run = Window1(root)
root.mainloop()
if __name__ == '__main__':
main()
I understand this is less practical, but I am curious. Cheers.
Tk() creates main window and variable root gives you access to this window. You can use root as argument for Window2 and you will have access to main window inside Window2
from tkinter import *
class Window1:
def __init__(self, master):
# keep `root` in `self.master`
self.master = master
self.label = Button(self.master, text="Example", command=self.load_new)
self.label.pack()
def load_new(self):
self.label.destroy()
# use `root` with another class
self.another = Window2(self.master)
class Window2:
def __init__(self, master):
# keep `root` in `self.master`
self.master = master
self.label = Label(self.master, text="Example")
self.label.pack()
root = Tk()
run = Window1(root)
root.mainloop()
--
Probably nobody use another class to create Label in place of Button ;)
--
EDIT: In this example using names Window1 and Windows2 is misleading because there is only one window and two classes which use this window. I would rather use names FirstOwner, SecondOwner
Everything is implemented in one Tk class and in this case there always is only one window.
from tkinter import *
from tkinter import ttk
class MainWindow():
def __init__(self, mainWidget):
self.main_frame = ttk.Frame(mainWidget, width=300, height=150, padding=(0, 0, 0, 0))
self.main_frame.grid(row=0, column=0)
self.some_kind_of_controler = 0
self.main_gui()
def main_gui(self):
root.title('My Window')
self.main_label_1 = ttk.Label(self.main_frame, text='Object_1')
self.main_label_1.grid(row=0, column=0)
self.main_label_2 = ttk.Label(self.main_frame, text='Object_2')
self.main_label_2.grid(row=1, column=0)
self.main_label_3 = ttk.Label(self.main_frame, text='Object_3')
self.main_label_3.grid(row=2, column=0)
self.setings_button = ttk.Button(self.main_frame, text='Setings')
self.setings_button.grid(row=0, column=1)
self.setings_button.bind('<Button-1>', self.setings_gui)
self.gui_elements = [self.main_label_1,
self.main_label_2,
self.main_label_3,
self.setings_button]
def setings_gui(self, event):
self.gui_elements_remove(self.gui_elements)
root.title('Setings')
self.main_label_1 = ttk.Label(self.main_frame, text='Object_1')
self.main_label_1.grid(row=2, column=0)
self.main_menu_button = ttk.Button(self.main_frame, text='Main menu')
self.main_menu_button.grid(row=0, column=1)
self.main_menu_button.bind('<Button-1>', self.back_to_main)
self.some_kind_of_controler = 1
self.gui_elements = [self.main_label_1,
self.main_menu_button]
def back_to_main(self, event):
if self.some_kind_of_controler == 1:
self.gui_elements_remove(self.gui_elements)
else:
pass
self.main_gui()
def gui_elements_remove(self, elements):
for element in elements:
element.destroy()
def main():
global root
root = Tk()
root.geometry('300x150+50+50')
window = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
I'm trying to pack the button below the Text and Scrollbar widget.
#!/usr/bin/python
try:
from Tkinter import *
except ImportError:
from tkinter import *
class Chat(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.pack(anchor=N, fill=BOTH)
self.create_widgets()
self.count = 0
def create_widgets(self):
self.scrolly = Scrollbar(self)
self.scrolly.pack(side=RIGHT, fill=Y)
self.chattext = Text(self, borderwidth=5, yscrollcommand=self.scrolly.set)
self.chattext.pack(side=LEFT)
self.scrolly.config(command=Text.yview(self.chattext))
self.button1 = Button(self, text="Add text", command=self.add_text)
self.button1.pack()
def add_text(self):
self.count += 1
self.chattext.insert("end", "%i\n" % self.count)
self.chattext.update_idletasks()
def main():
root = Tk()
root.title("Test Chat Client")
root.geometry("600x500")
#root.resizable(0,0)
app = Chat(root)
root.mainloop()
if __name__ == "__main__":
main()
This is what it looks like
I want the button to be below and not in between the other widgets.
I have tried the following:
self.button1.pack(after=self.scrolly)
self.button1.pack(after=self.chattext)
How may i pack the button at the bottom?
Another issue is that the scrollbar does not work, when i try to scroll nothing happens.
(Yes, i have tried to fill the Text widget with alot of lines, more than it can view.)
Also, why is the scrollbar viewed/packed outside/"far" away from the Text widget?
Try using the grid geometry manager instead.
http://www.tkdocs.com/tutorial/grid.html
I think you should consider replacing the text field with a ScrolledText field.
It's a lot easier to use and doesn't require manual scrollbar placement.
(Don't use pack to place it though. Use grid)
import tkinter as tk
import tkinter.scrolledtext as tkst
self.chattext = tkst.ScrolledText(
master = self,
wrap = tk.WORD,
width = 20,
height = 10
)