Keep a Frame in an other window Frame - python-2.7

My programm create a Frame with three panels in an horizontal boxsizer. A menu with "new window" item for create a seconde Frame. I give the seconde panel as parent of the seconde window. I wante the seconde Frame stays in the seconde panel area of my first frame.
if user move one of the two windows, the seconde stays in the panel screen area.
Do you know a way or something for that?
I tried a little something, but using is not very aesthetic.
and
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Python Test App',size=(600,400))
#Widgets
panel_gch = wx.Panel(self,-1,size = (150,-1))
panel_gch.SetBackgroundColour('white')
self.panel=wx.Panel(self,-1,size=(300,400))
self.panel.SetBackgroundColour((200,230,200))
panel_drt = wx.Panel(self,-1,size = (150,-1))
panel_drt.SetBackgroundColour('white')
box = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(box)
#Add
box.Add(panel_gch,0,wx.EXPAND)
box.Add(self.panel,1,wx.EXPAND)
box.Add(panel_drt,0,wx.EXPAND)
#Menu
status=self.CreateStatusBar()
menubar=wx.MenuBar()
file_menu=wx.Menu()
ID_FILE_NEW = 1
file_menu.Append(ID_FILE_NEW,"New Window","This is a new window")
menubar.Append(file_menu,"File")
self.SetMenuBar(menubar)
#bind and layout
self.Bind(wx.EVT_MENU, self.get_new_window)
panel_gch.Layout()
self.panel.Layout()
panel_drt.Layout()
self.Layout()
def get_new_window(self,event): # create new window
self.new = NewWindow(self.panel,-1)
self.new.Show(True)
self.new.Bind(wx.EVT_MOVE,self.window2_on_move)
def window2_on_move(self,event): # Window2 must stay in
x, y = event.GetPosition()
v,w =self.panel.GetScreenPosition()
s,t = self.panel.GetClientSizeTuple()
if x < v:
self.new.Move((v,-1))
if y < w:
self.new.Move((-1,w))
if x+200 > v+s:
self.new.Move((v+s-200,-1))
if y+200 > w+t:
self.new.Move((-1,w+t-200))
class NewWindow(wx.MiniFrame):
def __init__(self,MainWindow,id):
wx.MiniFrame.__init__(self, MainWindow, id, 'New Window', size=(200,200),\
style = wx.MINIMIZE | wx.CAPTION | wx.CLOSE_BOX | wx.CLOSE_BOX)
self.CenterOnParent()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=MainWindow(parent=None,id=-1)
frame.Show()
app.MainLoop()

What you probably want is AUI. I personally recommend the wx.lib.agw.aui set rather than wx.aui as the former is pure Python and has had a LOT more recent work done on it. There are multiple examples in the wxPython demo package. You can also read about it here:
http://wxpython.org/Phoenix/docs/html/lib.agw.aui.framemanager.AuiManager.html

Thanks you very much Mike, exactly what I needed.
With wxpython I found This way:
the child stays in the panel area and it follows the window parent when moving.
import wx
class MainWindow(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Python Test App',size=(600,400))
self.new = None
#Widgets
self.position = (0,0)
panel_gch = wx.Panel(self,-1,size = (150,-1))
panel_gch.SetBackgroundColour('white')
self.panel=wx.Panel(self,-1,size=(300,400))
self.panel.SetBackgroundColour((200,230,200))
panel_drt = wx.Panel(self,-1,size = (150,-1))
panel_drt.SetBackgroundColour('white')
box = wx.BoxSizer(wx.HORIZONTAL)
self.SetSizer(box)
#Add
box.Add(panel_gch,0,wx.EXPAND)
box.Add(self.panel,1,wx.EXPAND)
box.Add(panel_drt,0,wx.EXPAND)
#Menu
status=self.CreateStatusBar()
menubar=wx.MenuBar()
file_menu=wx.Menu()
ID_FILE_NEW = 1
file_menu.Append(ID_FILE_NEW,"New Window","This is a new window")
menubar.Append(file_menu,"File")
self.SetMenuBar(menubar)
#bind and layout
self.Bind(wx.EVT_MENU, self.get_new_window)
panel_gch.Layout()
self.panel.Layout()
panel_drt.Layout()
self.Layout()
def get_new_window(self,event): # create new window
if self.new == None:
self.win_one_move = False
self.new = NewWindow(self.panel,-1)
self.new.Show(True)
self.new.Bind(wx.EVT_MOVE,self.window2_on_move)
self.Bind(wx.EVT_MOVE,self.window1_on_move)
v,w =self.GetPosition()
x, y = self.new.GetPosition()
self.get_windows_position((x-v),(y-w))
def get_windows_position(self,x,y):
self.position = (x,y)
print "check",self.position
def window2_on_move(self,event): # Window2 must stay in
if self.win_one_move == False:
x, y = event.GetPosition()
v,w =self.panel.GetScreenPosition()
s,t = self.panel.GetClientSizeTuple()
new_x,new_y = self.new.GetClientSizeTuple()
if x < v:
self.new.Move((v,-1))
if y < w:
self.new.Move((-1,w))
if x+new_x > v+s:
self.new.Move((v+s-new_x,-1))
if y+new_y > w+t:
self.new.Move((-1,w+t-new_y))
v,w =self.GetPosition()
x,y = self.new.GetPosition()
self.get_windows_position((x-v),(y-w))
if self.win_one_move == True:
self.win_one_move = False
def window1_on_move(self,event):
self.win_one_move = True
print "1 move"
x,y = self.GetPosition()
self.new.Move((x+self.position[0],y+self.position[1]))
print self.position
class NewWindow(wx.MiniFrame):
def __init__(self,MainWindow,id):
wx.MiniFrame.__init__(self, MainWindow, id, 'New Window', size=(200,200),\
style = wx.CAPTION | wx.CLOSE_BOX | wx.CLOSE_BOX)
self.CenterOnParent()
if __name__=='__main__':
app=wx.PySimpleApp()
frame=MainWindow(parent=None,id=-1)
frame.Show()
app.MainLoop()
Can be use by another.Thanks

Related

How to print the variable of a class in python

I am trying to print the variable self.result. The ultimate goal is to use that for further processing, but for now just want to access the variable, so I chose it to print, however I am getting this message:
"wx._controls.StaticText; proxy of Swig Object of type 'wxStaticText *' at 0x23fed48> "
My code is below, any help is appreciated.
import wx
class ExampleFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.panel = wx.Panel(self)
self.quote = wx.StaticText(self.panel, label="is Awesome")
self.result = wx.StaticText(self.panel, label="")
self.result.SetForegroundColour(wx.RED)
self.button = wx.Button(self.panel, label="Save")
self.lblname = wx.StaticText(self.panel, label="Your name:")
self.editname = wx.TextCtrl(self.panel, size=(140, -1))
# Set sizer for the frame, so we can change frame size to match widgets
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
# Set sizer for the panel content
self.sizer = wx.GridBagSizer(5, 5)
self.sizer.Add(self.quote, (0, 1))
self.sizer.Add(self.result, (0, 0))
self.sizer.Add(self.lblname, (1, 0))
self.sizer.Add(self.editname, (1, 1))
self.sizer.Add(self.button, (2, 0), (1, 2), flag=wx.EXPAND)
# Set simple sizer for a nice border
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
# Use the sizers
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
# Set event handlers
self.button.Bind(wx.EVT_BUTTON, self.OnButton)
def OnButton(self, e):
self.result.SetLabel(self.editname.GetValue())
app = wx.App(False)
frame = ExampleFrame(None)
frame.Show()
print frame.result
app.MainLoop()
Your question makes no sense: Why would you want to read out the label of a static text? Its label (!, StaticText has no value) is set by the OnButton event, reading the value of the TextCtrl named editname (I think it is that what you are searching). But to answer your question: How to read a label from a StaticText change:
print frame.result
to
print frame.result.GetLabel() # or GetLabelText()
This will result in an empty string because the label is not set yet directly after frame creation.
See documentation parent object of StaticText.

Smooth scrolling text in Qlabel

I am trying to use a Qlabel as a message center for relaying messages to users of the application. Some messages might be longer than allowed for the Qlabel and I want it to just scroll horizontally until the end of the text. How can I do this in a Qlabel? I cannot seem to find anything in designer and don't want to work out some sort of truncation method in code that just takes off pieces from the front of the string, that seems silly.
What you are after is commonly known as Marquee widget. Here is a very simple and rusty implementation which make use of a QLabel, but it can be done with a QWidget too. I overridden the setText method from which i use a QTextDocument, with parent the QLabel itself, which holds the text. If the text is bigger than the size of the QLabel a QTimer triggers a translation method that moves the text:
import sys
from PyQt5.QtCore import QEvent, QTimer, pyqtSlot
from PyQt5.QtGui import QTextDocument, QPainter, QFontMetrics
from PyQt5.QtWidgets import QLabel, QApplication
class Marquee(QLabel):
x = 0
paused = False
document = None
speed = 50
timer = None
def __init__(self, parent=None):
super().__init__(parent)
self.fm = QFontMetrics(self.font())
self.setFixedSize(200, 20)
def setText(self, value):
self.x = 0
self.document = QTextDocument(self)
self.document.setPlainText(value)
# I multiplied by 1.06 because otherwise the text goes on 2 lines
self.document.setTextWidth(self.fm.width(value) * 1.06)
self.document.setUseDesignMetrics(True)
if self.document.textWidth() > self.width():
self.timer = QTimer(self)
self.timer.timeout.connect(self.translate)
self.timer.start((1 / self.speed) * 1000)
#pyqtSlot()
def translate(self):
if not self.paused:
if self.width() - self.x < self.document.textWidth():
self.x -= 1
else:
self.timer.stop()
self.repaint()
def event(self, event):
if event.type() == QEvent.Enter:
self.paused = True
elif event.type() == QEvent.Leave:
self.paused = False
return super().event(event)
def paintEvent(self, event):
if self.document:
p = QPainter(self)
p.translate(self.x, 0)
self.document.drawContents(p)
return super().paintEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Marquee()
w.setText('Lorem ipsum dolor sit amet, consectetur adipiscing elit...')
w.show()
sys.exit(app.exec_())
With a little bit changing #Daniele Pantaleone's code.I have implemented 3 mode of
Animations
i.e Left-to-Right,Right-to-Left & Left+Right .
It also supports Text Color and Marquee only work if text length exceeds the Label width.
Here is my code:
import sys
from PyQt5.QtCore import QEvent, QTimer, pyqtSlot,QRectF
from PyQt5.QtGui import QTextDocument, QPainter, QFontMetrics,QFont,QColor,QAbstractTextDocumentLayout,QPalette
from PyQt5.QtWidgets import QLabel, QApplication
class Document(QTextDocument):
def __init__(self, parent=None):
super().__init__(parent)
def drawContents(self, p, rect=QRectF()):
p.save()
ctx=QAbstractTextDocumentLayout.PaintContext ()
ctx.palette.setColor(QPalette.Text, p.pen().color())
if (rect.isValid()) :
p.setClipRect(rect)
ctx.clip = rect
self.documentLayout().draw(p, ctx)
p.restore()
class Marquee(QLabel):
paused = False
speed = 60
x=0
def __init__(self, parent=None):
super().__init__(parent)
self.document = None
self.timer = QTimer(self)
self.timer.timeout.connect(self.translate)
def setText(self, value,mode="LR"):
f=self.font()
self.fm=QFontMetrics(f)
if self.document is None:
self.document = Document(self)
self.document.setUseDesignMetrics(True)
self.document.setDefaultFont(f)
self.document.setDocumentMargin(0)
if self.timer.isActive() :
self.timer.stop()
if self.fm.width(value) > self.width():
self.nl = int(self.width()/self.fm.horizontalAdvance(" "))
val=' '*self.nl +value+' '*self.nl
self.document.setTextWidth(self.fm.width(val)+22 )
self.document.clear()
self.document.setPlainText(val)
self.setMode(mode)
self.timer.start((1 / 60) * 1000)
else:
self.x=(self.width()/2)-(self.fm.width(value)/2)
self.document.clear()
self.document.setPlainText(value)
self.repaint()
def setMode(self,val):
if val=="RL":
self.x = 0
elif val=="LR" :
self.x =-(self.document.textWidth()-self.fm.width(" "*self.nl)-10)
else:
self.x =-(self.document.textWidth()-self.fm.width(" "*self.nl)-10)
self.fstr=True
self.mode=val
#pyqtSlot()
def translate(self):
if not self.paused:
if self.mode=="RL":
if self.width() - self.x < self.document.textWidth():
self.x -= 1
else:
self.x=0
elif self.mode=="LR" :
if self.x<=0:
self.x+= 1
else:
self.x =-(self.document.textWidth()-self.fm.width(" "*self.nl)-10)
else:
if self.fstr:
if self.x<=0:
self.x+= 1
else:
self.x =0
self.fstr=False
else:
if self.width() - self.x < self.document.textWidth():
self.x -= 1
else:
self.x=-(self.document.textWidth()-self.fm.width(" "*self.nl)-10)
self.fstr=True
self.repaint()
def event(self, event):
if event.type() == QEvent.Enter:
self.paused = True
elif event.type() == QEvent.Leave:
self.paused = False
return super().event(event)
def getColor(self)->QColor:
if self.styleSheet()=='':
return QColor("grey")
else:
style =self.styleSheet().split(";")
color= "".join([s.split(":")[1] for s in style if s.startswith("color")])
return QColor(color)
def paintEvent(self, event):
if self.document:
p = QPainter(self)
self.getColor()
p.setPen(self.getColor())
p.translate(self.x, 0)
self.document.drawContents(p)
return super().paintEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Marquee()
w.setFixedSize(250, 60)
w.setStyleSheet("background-color:black;color:yellow")
f=QFont()
f.setPointSize(20)
f.setBold(True)
f.setItalic(True)
f.setFamily("Courier")
w.setFont(f)
w.setText("consectggftr_conversion_we want",mode="L+R") # or "RL" or "LR"
There is also better version of this Code provided by #eyllanesc Here
There's nothing in Qt that does that by default. You will indeed need to create an animation that changes the text.
You can use QFontMetrics (label.fontMetrics()) to determine if the label text is larger than then QLabel (to know if you need to scroll it or not). You need a way to repaint the QLabel every half second or so to animate the scrolling. The easiest way is probably a QTimer. The easiest method would probably be to subclass QLabel and have it check if it needs to scroll itself and reset the text every half second or so to simulate the scrolling.
If you wanted scrolling to be even smoother (at a sub-character level), you'd have to override the paint method and paint the text yourself translating and clipping it as necessary.

Trouble auto labelling buttons from database then centering them in a frame

class ManageExistingColleaguePanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
main_sizer = wx.BoxSizer(wx.VERTICAL)
con = sqlite3.connect("hs_audit.sqlite")
con.text_factory = str
cur = con.cursor()
cur.execute("SELECT engineer FROM T1")
myList = [r[0] for r in cur.fetchall()]
con.close()
main_sizer.AddStretchSpacer()
for n in range(0, len(myList)):
main_sizer.Add(wx.Button(self, wx.CENTER, label = str(myList[(n)]), size = (200, 35)))
main_sizer.AddStretchSpacer()
self.SetSizer(main_sizer)
I have been trying to get a column of buttons centered in the frame labeled with the contents of a column in a mysqlite3 table.
I can get the buttons in a column all labelled but can't get them centered. I have tried loads of different combinations to get this right, but get errors regarding undefined label or size variables. I can get a centered column of buttons but then I am unable to label them.
Any help please this is driving me mad.
At last. Can't seem to get the hang of the wxpython sizer syntax's.
Anyways here was the answer.
class ManageExistingColleaguePanel(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
main_sizer = wx.BoxSizer(wx.VERTICAL)
con = sqlite3.connect("hs_audit.sqlite")
con.text_factory = str
cur = con.cursor()
cur.execute("SELECT engineer FROM T1")
myList = [r[0] for r in cur.fetchall()]
con.close()
main_sizer.AddStretchSpacer()
for n in range(0, len(myList)):
main_sizer.Add(wx.Button(self, label=str(myList[(n)]), size=(200, 35)), 0, wx.CENTER)
main_sizer.AddStretchSpacer()
self.SetSizer(main_sizer)

Tkinter cell location (x,y)?

Is there a way to get the cell size and x,y location of a cell's corner?I have radio buttons on the left side of my frame and I would like to resize an image based on the size of the frame.
What I'm going to end up doing is creating a block that takes up a large group of cells that will allow me to zoom in on my .tif and scroll left/right and up/down. Does this type of widget already exist?
Here's a very rough outline of what I currently have
from tkinter import *
from PIL import Image,ImageTk
import os
file_path = "C:/Users/..."
dirs = os.listdir(file_path)
root = Tk()
# Set window size slightly below screen size
width = int(root.winfo_screenwidth() - root.winfo_screenwidth()/9)
height = int(root.winfo_screenheight() - root.winfo_screenheight()/9)
root.geometry(str(width)+"x"+str(height))
class Application(Frame):
def __init__(self,master):
Frame.__init__(self,master)
os.chdir(file_path)
self.grid()
self.create_widgets()
def create_widgets(self):
Label(self,
text = "Available Files"
).grid(row=0,column=0,sticky=W)
Label(self,
text = "Select one:"
).grid(row=1,column=0,sticky=W)
self.filelist = StringVar()
self.filelist.set(0)
# Radio buttons of files in directory
i = 1
for files in dirs:
if os.path.isfile(os.path.join(file_path, files)):
i += 1
Radiobutton(self,
text=files,
variable=self.filelist,
value=files,
command=self.update_text
).grid(row=i,column=0,sticky=W)
# Message box
self.result = Text(self, width=40, height=5, wrap=WORD)
self.result.grid(row=i, column=0, columnspan=3)
def update_text(self):
message = "File selected is "
message += self.filelist.get()
self.display_image()
self.result.delete(0.0, END)
self.result.insert(0.0, message)
def display_image(self):
try:
self.image = Image.open(self.filelist.get())
except:
message += self.filelist.get() + " doesn't exist. This is awkward..."
img_width,img_height = self.image.size
self.preview_image = ImageTk.PhotoImage(self.image)
self.preview = Label(self, image=self.preview_image)
self.preview.grid(row=0, column=3, rowspan=20)
app = Application(root)
root.mainloop()

Aligning Label in Frame Tkinter

I am new to Python and even newer to Tkinter.
I am currently practicing how to use Frames and Labels and
the problem I am encountering is, when I put Labels on a frame with some buttons next to each label,
the alignment is not good to look at.
Here is the code:
from Tkinter import *
class GUI():
def __init__(self):
self.namelist = ["Mark","Anna","Jason","Lenna","Leo","Zucharich","Robinson","AReallyLongNameThatMightExist"]
self.canvas = Canvas(width=1200,height=700)
self.canvas.pack(expand=YES,fill=BOTH)
def Friends(self):
controlframe = Frame(self.canvas)
controlframe.place(x=600,y=300)
#Frame for showing names of friends
for x in self.namelist:
frame = Frame(controlframe)
frame.pack()
Name = Label(frame,text="%s "%x).pack(side=LEFT)
chatButton = Button(frame,text="Chat").pack(side=LEFT)
delButton = Button(frame,text="Delete").pack(side=LEFT)
setcloseButton = Button(frame,text="Set Close").pack(side=LEFT)
setgroupButton = Button(frame,text="Set Group").pack(side=LEFT)
mainloop()
GUI = GUI()
GUI.Friends()
What should I do so that the alignment of the Label(=name) and the button is equal to the other ones so that they will form a shape of a rectangle and not some zigzag?
It is almost always better in Tk to use the grid geometry manager. It is much more flexible once you come to understand how it works. Converting your example to use grid solves your problem as shown below but you should experiment with it a bit. Try removing the 'sticky="W"' from the label for instance and see that the centering of the widgets within the row or column can be controlled. To get your frame responding to resizes sensibly you should investigate the columnconfigure and rowconfigure options for the grid geometry management as well.
from Tkinter import *
class GUI():
def __init__(self):
self.namelist = ["Mark","Anna","Jason","Lenna",
"Leo","Zucharich","Robinson",
"AReallyLongNameThatMightExist"]
self.canvas = Canvas(width=1200,height=700)
self.canvas.pack(expand=YES,fill=BOTH)
def Friends(self):
frame = Frame(self.canvas)
frame.place(x=600,y=300)
#Frame for showing names of friends
row = 0
for x in self.namelist:
label = Label(frame,text="%s "%x)
chatButton = Button(frame,text="Chat")
delButton = Button(frame,text="Delete")
setcloseButton = Button(frame,text="Set Close")
setgroupButton = Button(frame,text="Set Group")
label.grid(row=row, column=0, sticky="W")
chatButton.grid(row=row, column=1)
delButton.grid(row=row, column=2)
setcloseButton.grid(row=row, column=3)
setgroupButton.grid(row=row, column=4)
row = row + 1
mainloop()
GUI = GUI()
GUI.Friends()