Hiding popup frame with witdraw() results in unfitted window size - python-2.7

I'm creating a popup window in tkinter and want to hide it until it is created, labeled and centered on the screen to prevent the window to briefly flash empty at the wrong position.
But if i implemente these the resulting window acts if its contents were never distributed by pack() and the size of the window is set to a default 200 x 200 px.
I also tried after() and update_idletasks() since i guessed the issue in the sequence of drawing but with no success.
To hide it i use the withdraw() and deiconify() functions as stated in many other Posts including this one:
Tkinter - Preload window?
My resulting code looks like this:
Frame creation
class NotificationPopup(Tk.Toplevel):
def __init__(self, root, text, title):
Tk.Toplevel.__init__(self, root)
# Hide window until created
self.withdraw()
# Slaved to parent. Shown over parent window
self.transient(root)
# Stops interaction with parent until child is solved
self.grab_set()
self.label = Tk.Label(self, text=text, justify=Tk.LEFT, padx=10)
self.label.pack()
self.button = Tk.Button(self, text='Ok', command=self.destroy)
self.button.pack()
self.button.focus_set()
self.resizable(False, False)
self.relief = Tk.GROOVE
# Bind return to the button to close the window
self.button.bind('<Return>', (lambda event: self.destroy()))
Toolbox.center_toplevel(self)
# Show window
self.deiconify()
Center method
# Center a window based on screen dimensions and window size
def center_toplevel(toplevel):
toplevel.update_idletasks()
# Toplevel window dimensions
w = toplevel.winfo_width()
h = toplevel.winfo_height()
# get screen width and height
ws = toplevel.winfo_screenwidth() # width of screen
hs = toplevel.winfo_screenheight() # height of screen
# calculate x and y coordinates for the Tk root window
x = (ws / 2) - (w / 2)
y = (hs / 2) - (h / 2)
# Set dimension of window and placement on screen
toplevel.geometry('%dx%d+%d+%d' % (w, h, x, y))
Running the code without withdraw() on my application Shows the width and heigt at 450 and 400 px while including withdraw() shrinks it to 200 x 200 px and don't refit it to it's content.

Related

Mouse click results in unexpected behavior using wxPython & wx.Panel

I am writing an application in which the following steps are intended to be executed:
1 - user clicks in blue area (a wx.Panel) and a white circle appears;
2 - user clicks Select Start button;
3 - user clicks in the white circle and it changes to green (by drawing a green circle over the white one)
The problem is that when step 3 is executed the green circle does not appear where the mouse is clicked. For example, clicking in the blue area registers a point at (223, 486). After clicking the Select Start button and then clicking in the white circle a point registers at (211, 464), and a green circle appears outside the white circle. I don’t understand why this is happening and would appreciate any help in resolving the problem.
Using python 2.7 with wxPython 3.0.3.0 on MacOs
import wx
class Test(wx.Frame):
def __init__(self, parent, title):
super(Test, self).__init__(parent, title = title, size = (820,900))
self.startSelected = False
self.radius = 10
self.panel = wx.Panel(self, size=(800,800))
self.panel.SetBackgroundColour(wx.Colour(0,0,200))
self.panel.Bind(wx.EVT_LEFT_DOWN, self.onMouseDown)
self.gbs = wx.GridBagSizer(0,0)
self.startBtn = wx.Button(self, wx.ID_ANY, label = 'Select Start')
self.startBtn.Bind(wx.EVT_BUTTON, self.selectStart)
self.gbs.Add(self.panel, span = (1,4), pos=(1,1),flag=wx.EXPAND | wx.ALL)
self.gbs.Add(self.startBtn, pos=(2,1))
self.SetSizer(self.gbs)
def onMouseDown(self, e):
pt = e.GetPosition()
print pt.x, pt.y
if e.LeftDown():
if self.startSelected:
color = wx.Colour(0,255,0)
self.paint(pt, color)
else:
color = wx.Colour(255,255,255)
self.paint(pt, color)
def paint(self, pt, color):
dc = wx.ClientDC(self)
b = wx.Brush(color)
dc.SetBrush(b)
dc.DrawCircle(pt.x, pt.y, self.radius)
def selectStart(self, e):
self.startSelected = True
if __name__ == '__main__':
app = wx.App()
Test(None, 'Test')
app.MainLoop()
The wx.ClientDC is relative to the object passed to it. As coded in the paint method, dc = wx.ClientDC(self), self is the wx.Frame. Since drawing is done on the wx.Panel, dc = wx.ClientDC(self.panel) should be used. This results in the expected behavior.

Placing buttons adjacent to each other inside a frame using tkinter

import Tkinter as tk
import tkMessageBox as tkmb
# globals
buttons = {}
root = None
# Root Window
root = tk.Tk()
root.wm_title('buttons')
# connect button
comButtonFrame = tk.Frame(root)
label = tk.Label(comButtonFrame, text = 'Open Connection')
label.grid(row=0, column=0, sticky=tk.W)
comPortButtonConnect = tk.Button(comButtonFrame, text='Connect', width=10)
buttons['connect']=comPortButtonConnect
# disconnect button
comPortButtonDisconnect = tk.Button(comButtonFrame, text='Disconnect', width=10)
buttons['disconnect'] = comPortButtonDisconnect
# Program device button
comPortButtonProgram = tk.Button(comButtonFrame, text='Program',width=10)
buttons['program'] = comPortButtonProgram
# display button in a grid
comPortButtonConnect.grid(row=1, column=0, sticky=tk.W)
comPortButtonDisconnect.grid(row=2, column=0, sticky=tk.W)
comPortButtonProgram.grid(row=2, column=1, sticky=tk.W)
comButtonFrame.pack(anchor=tk.W, fill=None, side=tk.TOP, pady=30)
w = root.winfo_width() + 600 # width for the Tk root
h = root.winfo_height() + 830 # height for the Tk root
# get screen width and height
ws = root.winfo_screenwidth() # width of the screen
hs = root.winfo_screenheight() # height of the screen
# calculate x and y coordinates for the Tk root window top left corner
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
# set the dimensions of the window
# and where it is placed
root.geometry('%dx%d+%d+%d' % (w, h, x, y))
# start in fullscreen mode
# root.attributes('-fullscreen', True)
# run GUI
root.mainloop()
I am not able to get the disconnect and program buttons to be closer to each other. Any suggestions on how that can be done ? This is what it looks like right now. In the code I posted, ignore the callbacks. You can delete the option to get it to run. Its not relevant since I only want to know how to fix the display.

How to keep a Tkinter widget on top of the others

I have some code that moves images left and right but I do not want them to appear on top of the right border, which I draw as a rectangle.
What are the options in Tkinter to keep a widget (in my example a rectangle) on top of some other widgets (in my code a tile, which is an image)?
I am drawing the rectangle and the image on one canvas.
I can image that using two canvas could do the trick, but are there any other options/settings?
Thanks
import Tkinter as tk # for Python2
import PIL.Image, PIL.ImageTk
win = tk.Tk()
#Create a canvas
canvas = tk.Canvas(win, height = 500, width = 500)
#Create a rectangle on the right of the canvas
rect = canvas.create_rectangle(250, 0, 500, 250, width = 2, fill = "red")
#Create an image
SPRITE = PIL.Image.open("sprite.png")
tilePIL = SPRITE.resize((100, 100))
tilePI = PIL.ImageTk.PhotoImage(tilePIL)
tile = canvas.create_image(100, 100, image = tilePI, tags = "a tag")
#Place the canvas
canvas.grid(row = 1, column = 0, rowspan = 5)
#Move the tile to the right.
#The tile will go on top of red rectangle. How to keep the rectangle on top of the tile?
canvas.coords(tile, (300, 100))
canvas.mainloop()
Use tag_raise() method:
canvas.tag_raise(tile)

Recurive game in pygame, using recursive rectangles.(pygame)

Ive been trying to make a recursive rectangles and I wanted to make the rectangles move in the forward direction like each time it recursed, so that it gives a motion as one is going into an endless rectangles. Ive tried making the size bigger each time it recursed but failed as it wont recurse or nothing would show up. Any tips or how to do this would be appreciated. This sample I implemented from pygamearcade. I want to get the feeling as one is going into the rectangles and that can be implemented as the rectangles get bigger each time it goes through recurion. So any tips or how to do it is fine. Thank you
import pygame
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, WHITE,
[x, y, width, height],
1)
speed = [10,0]
# Is the rectangle wide enough to draw again?
while (width > 14):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
pygame.init()
#rectanglelist = [big()]
# Set the height and width of the screen
size = [700, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(BLACK)
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
recursive_draw(0, 0, 700, 500)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
The problem is that your recursive_draw() function is not really a recursive function, because a recursive function is a function that conditionally calls itself:
Every properly designed recursive function must have at least one base case [A] and must redefine the problem into sub problems that work towards a base case [B].
def countdown(n):
if n < 1:
print "Lift Off" #[A]
else:
print n
countdown(n - 1) #[B]
What you could do for your code:
First fix the indent of your code.
Second, replace your while loop by an ´if´ statement.
This is the important part or recursion: The function calls itself unless a certain condition is not true anymore (in your case width > 14). For more information see How can I build a recursive function in python? or Recursion function in python on SO.
The updated function (code from http://www.balloonbuilding.com/ by Paul Vincent Craven):
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, BLACK, (x, y, width, height), 1)
# Is the rectangle wide enough to draw again?
if(width > 14):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
I hope this helps :)
EDIT:
The updated program:
import pygame
# Colors
BLUE = (55, 155, 255)
WHITE = (255, 255, 255)
def recursive_draw(x, y, width, height):
""" Recursive rectangle function. """
pygame.draw.rect(screen, WHITE, (x, y, width, height), 2)
# Is the rectangle wide enough to draw again?
if(width > 14):
# Scale down
x += width * .1
y += height * .1
width *= .8
height *= .8
# Recursively draw again
recursive_draw(x, y, width, height)
speed = [10,0]
pygame.init()
#rectanglelist = [big()]
# Set the height and width of the screen
size = [700, 500]
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Set the screen background
screen.fill(BLUE)
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
recursive_draw(0, 0, 700, 500)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 60 frames per second
clock.tick(60)
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
Screenshot:

Draggable point in matplotlib - How to retrieve point coordinates

I would like to be able to move a point (matplotlib.patches.Ellipse) along a vertical line. To do so, I'm calling the Dragable rectangle class (http://matplotlib.org/1.3.1/users/event_handling.html) inside a PySide QtGui.QWidget.
The dragging of my ellipse works fine, but I'm stuck in how to retrieve the final y-coordinate of the ellipse when I release the mouse button (I want to have a QLabel next to the plot that contains this y-coordinate). From on_release I have its final position:
def on_release(self, event):
if DraggablePoint.lock is not self:
return
self.point.newYcoordinate = self.point.center[1]
self.press = None
DraggablePoint.lock = None
# draw everything but the selected point and store the pixel buffer
canvas = self.point.figure.canvas
axes = self.point.axes
self.point.set_animated(True)
canvas.draw()
self.background = canvas.copy_from_bbox(self.point.axes.bbox)
# now redraw just the point
axes.draw_artist(self.point)
# and blit just the redrawn area
canvas.blit(axes.bbox)
but how can I connect this to the text of my QLabel (and obtain that this label is updated each time the ellipse is moved)?
self.FlexibleValue = patches.Ellipse(xy=(0.5, 0.5), width=0.2, height=0.2, edgecolor='r', facecolor='r', lw=2)
self.axesResp.add_patch(self.FlexibleValue)
self.dragValue = DraggablePoint(self.FlexibleValue)
self.dragValue.connect()
by adding a signal as tcaswell suggested:
def on_release(self, event):
...
self.signal.updatedSignal.emit(str(self.point.newYcoordinate))
and then retrieving the y-coordinate:
self.dragValue.signal.updatedSignal.connect(self.updatedValue)
with:
def updatedValue(self, newValue):
self.labelValue.setText(newValue)
and:
class UpdatedSignal(QtCore.QObject):
updatedSignal = QtCore.Signal(str)