I'm using python,pygame and PGU to develop a game. I'd like to create a fixed size button, but it seems resize() doesn't have any effect. Here is a snippet of my code:
app = gui.App()
top = gui.Container()
button = gui.Button("Start")
button.resize(200, 100)
top.add(button, 0, 0)
app.init(top, screen)
The button will always appear at the minimum size required to display its text. Is there any way to enforce the button size with PGU?
If you want to create a fixed size button, you should initialize it, passing width and height.
Remember that, if the dimensions in pixel aren't "large enough", it forces the button to have the minimum size required to display its text, also considering padding (from style/theme, which you can also configure) etc.
Theese are three useful (of course alternative) examples:
button = gui.Button("Start", width = 200)
button = gui.Button("Start", height = 100)
button = gui.Button("Start", width = 200, height = 100)
Where the one you are looking for is the last.
The question is rather old, but still useful for others, I think.
Related
I was wondering how do the geometry() function values in tkinter come to play with the height value of for example a scrolled text? How can I convert the units to work with each other?
For example: If I want to open a scrolled text box underneath my tkinter window with a click of a button, I know I need then to change my window's geometry() (height) value, but I don't know by how much exactly.
(In the following example I randomly added 100 to the geometry value in the function open. But I want a more specific value that translates to the 7 of the height value of the scrolled text)
from tkinter import *
from tkinter import scrolledtext
def open():
root.geometry(f'{frame_width}x{frame_height+100}')
st.pack(side="bottom")
frame_width = 900
frame_height = 500
root = Tk()
root.geometry(f'{frame_width}x{frame_height}')
root.configure(bg='white')
root.resizable(False, False)
open_st = Button(root, text="OPEN SCROLLED TEXT", command= open)
open_st.pack()
st = scrolledtext.ScrolledText(root, width=frame_width, height=7)
root.mainloop()
Widgets that contains text usually provide their width and height in character space. This means tkinter takes the average width and height of your font and multiplies it with the given number in width and height.
There are mainly two ways to deal with that, either tk.Font.measure or metrics, if you want to convert characters to pixel or the much more comfortable way by just asking the widget for it's size via winfo. Happily your case fits for the latter.
The alternate code would looks like this:
def open_text():
st.pack(side="bottom")
width, window_height = root.winfo_width(), root.winfo_height()
requested_text_height = st.winfo_reqheight()
new_height = window_height + requested_text_height
root.geometry(f'{width}x{new_height}')
Please note that I have named your function differently. Cause you redefined open in the global namespace of your module and this could lead to unintended behavior. In addition I wonder why you want to do it like this and not just let the geometry managers do their job?
I want to create a side bar like the one ABOVE that is collapsible.
In the collapsed form, the side bar will only have icons for the option and when you hover your mouse over the bar then it will expand showing you the description/name of the icon.
If you click on the icon then it will take you to a function designated to that icon such as settings page.
On the right I will have the main home page with a lot of buttons.
I have no clue how you would do this so please help me start this off and I should manage with the rest.
Is it also possible to do this with only the basic Tkinter or do I need to import more modules via pip (not preferable)
So far I have this:
def loginnow(name):
global login
login.destroy()
login= Tk()
screen_width = login.winfo_screenwidth()
screen_height = login.winfo_screenheight()
screen_height=str(screen_height)
screen_width=str(screen_width)
screen = screen_width+"x"+screen_height
login.geometry(screen)
login.title("Logged in as %s"%name)
The side bar will include
Settings = https://www.iconpacks.net/icons/2/free-settings-icon-3110-thumb.png
I will manage with the other icons, once I get a general idea.
I want the menu to be visible without having to click on something for it to appear.
Explanation:
This can actually be achieved by playing around with bindings. Take a look at this rough example below:
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
root.geometry('600x600')
min_w = 50 # Minimum width of the frame
max_w = 200 # Maximum width of the frame
cur_width = min_w # Increasing width of the frame
expanded = False # Check if it is completely exanded
def expand():
global cur_width, expanded
cur_width += 10 # Increase the width by 10
rep = root.after(5,expand) # Repeat this func every 5 ms
frame.config(width=cur_width) # Change the width to new increase width
if cur_width >= max_w: # If width is greater than maximum width
expanded = True # Frame is expended
root.after_cancel(rep) # Stop repeating the func
fill()
def contract():
global cur_width, expanded
cur_width -= 10 # Reduce the width by 10
rep = root.after(5,contract) # Call this func every 5 ms
frame.config(width=cur_width) # Change the width to new reduced width
if cur_width <= min_w: # If it is back to normal width
expanded = False # Frame is not expanded
root.after_cancel(rep) # Stop repeating the func
fill()
def fill():
if expanded: # If the frame is exanded
# Show a text, and remove the image
home_b.config(text='Home',image='',font=(0,21))
set_b.config(text='Settings',image='',font=(0,21))
ring_b.config(text='Bell Icon',image='',font=(0,21))
else:
# Bring the image back
home_b.config(image=home,font=(0,21))
set_b.config(image=settings,font=(0,21))
ring_b.config(image=ring,font=(0,21))
# Define the icons to be shown and resize it
home = ImageTk.PhotoImage(Image.open('home.png').resize((40,40),Image.ANTIALIAS))
settings = ImageTk.PhotoImage(Image.open('settings.png').resize((40,40),Image.ANTIALIAS))
ring = ImageTk.PhotoImage(Image.open('ring.png').resize((40,40),Image.ANTIALIAS))
root.update() # For the width to get updated
frame = Frame(root,bg='orange',width=50,height=root.winfo_height())
frame.grid(row=0,column=0)
# Make the buttons with the icons to be shown
home_b = Button(frame,image=home,bg='orange',relief='flat')
set_b = Button(frame,image=settings,bg='orange',relief='flat')
ring_b = Button(frame,image=ring,bg='orange',relief='flat')
# Put them on the frame
home_b.grid(row=0,column=0,pady=10)
set_b.grid(row=1,column=0,pady=50)
ring_b.grid(row=2,column=0)
# Bind to the frame, if entered or left
frame.bind('<Enter>',lambda e: expand())
frame.bind('<Leave>',lambda e: contract())
# So that it does not depend on the widgets inside the frame
frame.grid_propagate(False)
root.mainloop()
I have explained the code using comments to understand on-the-go. The icons where taken from Flat Icons. As can be seen, it has its own disadvantage, but you can quite mimic something closer to what you have shown, with this. You can improve this more by creating custom widgets to hold both icon and text when expanded and so on.
Output:
Updated image code(without PIL):
home = PhotoImage(file='home.png') # Make sure the image size is comparable to the minimum frame width
settings = PhotoImage(file='settings.png')
ring = PhotoImage(file='ring.png')
Although tkinter doesn't have anything like this built-in, you have all of the tools to implement it. You start by creating a frame to hold the sidebar, and then bind to the <Enter> and <Leave> events on the frame to show and hide it.
There are at least three ways to show and hide it. For example, if each item was a button with an image and text and added to the frame with pack you could simply add or remove the text portion of the button to cause it to shrink or example.
Or, if using grid and creating the icon and text as separate widgets, you could use grid_remove to remove everything in the second column, causing the frame to shrink.
Or, you could use place to add the sidebar to the root window, and use place to change the width of the frame when you show or hide it.
I am trying to place images next to each other side by side but the labels overlap and the label sticks out.
from tkinter import *
root = Tk()
root.geometry("1000x700")
root.resizable(0, 0)
##############################################
TFi = PhotoImage(file="images/Topframe.png")
TF = Label(root, image=TFi)
TF.place(x=-3, y=-3)
BFi = PhotoImage(file="images/Botframe.png")
BF = Label(root, image=BFi)
BF.place(x=-3, y=650)
LF1i = PhotoImage(file="images/LeftFrame1.png")
LF1 = Label(root, image=LF1i)
LF1.place(x=-3, y=50)
##############################################
root.mainloop()
Is it possible to place an image in Tkinter without a Label or canvas
Your most common choices for labels are a canvas or a label. You can also put images on buttons, and embed them in a text widget.
The best choice for creating labels that are next to each other are to use pack or grid. pack is good if you're making a single horizontal or vertical grouping, but grid is better if you're making both rows and columns of widgets.
You can use place, but that requires that you do all of the math to compute the location of each image, and usually results in a user interface that isn't very resilient to changes in screen resolution. It also sometimes ends up causing you to have to do changes to every widget even if you only want to tweak the layout slightly.
My guess for why they overlap is that you aren't aware that the coordinates you give place by default specify the center of the image rather than the upper-left corner. You can specify which part of the image is at the given coordinate with the anchor option.
the label sticks out.
I'm not exactly sure what you mean by that, but if you mean that it has a 3D appearance, you can control that by giving it a borderwidth of zero and/or a relief of "flat".
I'm trying to change the width of a Message widget in Tkinter by using the width parameter. I couldn't get it to work so I tried align, justify and aspect which all produced the same result - the box remains centred and the width of the text.
Here is my code:
console_Fetch = Message(text="test\ntest\ntest\ntest\ntest",bd=1,relief="sunken",width=300)
console_Fetch.grid(row=7,column=0,padx=5,pady=1,columnspan=2)
I'm obviously using .grid() to pack it into the window.
Here's a screenshot of my window:
Pragmatic answer
Often setting width in widgets is not working as expected, depending on priority of other aspects, cell width, you name it. It gets easily overruled, or depends on other conditions.
What I always do is give the grid a "skeleton" of canvases in adjecent cells, with height (or width) of zero. Subsequently stretch the widget with sticky inside their cells. Just look at the example below:
from tkinter import *
win = Tk()
console_Fetch = Message(text="test\ntest\ntest\ntest\ntest",bd=1,relief="sunken",width=3000)
canvas = Canvas(width = 500, height = 0)
canvas.grid(row=0,column=0)
console_Fetch.grid(row=1,column=0,padx=5,pady=1,columnspan=2, sticky = N+W+E+S)
win.mainloop()
The same I did in shaping the grid in the minesweeper- matrix in this answer.
We are writing a program to display a video from a microscope. The size of the video is 2208 * 1648. This is much bigger than the available screensize. So I use a QScrollArea to show it.
self.scrollArea = QScrollArea(self)
self.scrollArea.setBackgroundRole(QPalette.Dark)
self.scrollArea.setWidget(self.imageLabel)
self.scrollArea.setWidgetResizable(True)
This scales the video to the size of the viewport. So initialy the video is shown completely in the viewport of the scrollarea without scrollbars. Now it must be possible to zoom in on a particular part of the video. So a zoomfactor can be entered. When this is done the following code is executed:
def scaleImage(self, factor):
self.scrollArea.setWidgetResizable(False)
self.imageLabel.resize(factor * self.imageLabel.pixmap().size())
self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor)
self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor)
When the actual video is shown, the images are sent to the label using the following function
def set_image(self, pixmap):
self.imageLabel.set_image(pixmap, self.current_width, self.current_height)
self.imageLabel.resize(self.current_zoomfactor * self.imageLabel.pixmap().size())
This works. However there are several problems:
1. setWidgetResizable does not honor the aspectratio
2. When a user zooms out, eventually the picture becomes smaller than the viewport, which is not what I want.
3. I tried to get the size of the viewport using
sizehint = self.scrollArea.viewportSizeHint()
Then I do get a size which looks more or less correct, however when I resize the window the result does not change.
Thanks a lot in advance
Before the resize the zoom factor is calculated:
def handle_min_zoomfactor(self, new_zoomfactor):
self.minimal_zoom = self.scrollArea.viewport().width() / self.sensor_width
if new_zoomfactor < self.minimal_zoom:
new_zoomfactor = self.minimal_zoom
if new_zoomfactor > 1.0:
new_zoomfactor = 1
After that scaleImage is called.