I have a button to copy text from a TextCtrl
and I want to display a message next to it to confirm that the text has been copied to the clipboard. So I'm using a StaticText
that hides and shows when the button is clicked.
I have put the button and the StaticText
in a horizontal centred BoxSizer
. The thing is when the StaticText
shows, as the BoxSizer
's children are centred it moves them. Here is my code:
def __init__(self, *args, **kw) -> None:
super(Window, self).__init__(*args, **kw)
# create a panel in the frame
pnl = wx.Panel(self)
# create some widgets in the panel
self.text_area1 = wx.TextCtrl(pnl, style=wx.TE_MULTILINE | wx.TE_NOHIDESEL)
self.text_area2 = wx.TextCtrl(pnl, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_NOHIDESEL | wx.TE_RICH2)
btn_correct = wx.Button(pnl, label="Correct >>>")
btn_correct.Bind(wx.EVT_BUTTON, self.on_press_correct)
self.btn_copy = wx.Button(pnl, label="Copy")
self.btn_copy.Bind(wx.EVT_BUTTON, self.on_press_copy)
self.label = wx.StaticText(pnl, label="Text copied")
self.label.Hide()
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
# create a sizer to manage the layout of child widgets
sizer = wx.BoxSizer(wx.VERTICAL)
sub_sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(self.text_area1, 1, wx.ALL | wx.EXPAND, 5)
sizer.Add(btn_correct, 0, wx.ALL | wx.CENTER, 5)
sizer.Add(self.text_area2, 1, wx.ALL | wx.EXPAND, 5)
sub_sizer.Add(self.btn_copy, 0, wx.ALL | wx.CENTER, 5)
sub_sizer.Add(self.label, 0, wx.ALL | wx.CENTER, 5)
sizer.Add(self.sub_sizer, 0, wx.BOTTOM | wx.CENTER, 5)
pnl.SetSizer(sizer)
def on_press_copy(self, event):
data_obj = wx.TextDataObject()
data_obj.SetText(self.text_area2.GetValue())
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(data_obj)
wx.TheClipboard.Close()
self.btn_copy.Disable()
self.label.Show()
self.label.GetParent().GetSizer().Layout()
self.timer.StartOnce(3000)
else:
wx.MessageBox("Can't open clipboard", "Error")
def on_timer(self, event):
self.btn_copy.Enable()
self.label.Show(show=False)
self.label.GetParent().GetSizer().Layout()
How can I achieve that without moving the button when the StaticText
shows?
CodePudding user response:
I have added a dummy element (filler - size >= length of label text) and used that to the left of the button and created a sizer (label_sizer which contains the filler element) to the right. That means the button does not move when the text is shown
import wx
class MainFrame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(None, *args, **kwargs)
self.Title = 'Wx App'
self.panel = MainPanel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.panel)
self.SetSizer(sizer)
self.Center()
self.Show()
class MainPanel(wx.Panel):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
# create some widgets in the panel
self.text_area1 = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_NOHIDESEL)
self.text_area2 = wx.TextCtrl(self, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_NOHIDESEL | wx.TE_RICH2)
btn_correct = wx.Button(self, label="Correct >>>")
btn_correct.Bind(wx.EVT_BUTTON, self.on_press_correct)
self.btn_copy = wx.Button(self, label="Copy")
self.btn_copy.Bind(wx.EVT_BUTTON, self.on_press_copy)
self.label_text = "Text copied"
filler = (100, 0)
self.label = wx.StaticText(self, label=self.label_text)
self.label.Hide()
self.label_dummy = filler
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
# create a sizer to manage the layout of child widgets
sizer = wx.BoxSizer(wx.VERTICAL)
sub_sizer = wx.BoxSizer(wx.HORIZONTAL)
label_sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.text_area1, 1, wx.ALL | wx.EXPAND, 5)
sizer.Add(btn_correct, 0, wx.ALL | wx.CENTER, 5)
sizer.Add(400,0)
label_sizer.Add(filler)
label_sizer.Add(self.label)
sizer.Add(self.text_area2, 1, wx.ALL | wx.EXPAND, 5)
sub_sizer.Add(self.label_dummy, 0, wx.ALL | wx.CENTER, 5)
sub_sizer.Add(self.btn_copy, 0, wx.ALL | wx.CENTER, 5)
sub_sizer.Add(label_sizer, 0, wx.ALL | wx.CENTER, 5)
sizer.Add(sub_sizer, 0, wx.BOTTOM | wx.CENTER, 5)
self.SetSizer(sizer)
def on_press_copy(self, event):
data_obj = wx.TextDataObject()
data_obj.SetText(self.text_area2.GetValue())
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(data_obj)
wx.TheClipboard.Close()
self.btn_copy.Disable()
self.label.Show()
self.label.GetParent().GetSizer().Layout()
self.timer.StartOnce(3000)
else:
wx.MessageBox("Can't open clipboard", "Error")
def on_press_correct(self, event):
print('Correct')
def on_timer(self, event):
self.btn_copy.Enable()
self.label.Show(show=False)
self.label.GetParent().GetSizer().Layout()
if __name__ == '__main__':
wx_app = wx.App()
MainFrame()
wx_app.MainLoop()
CodePudding user response:
For reference, a partial code snippet, with errors, won't help get your question attention.
Obviously, centring 1 item versus 2 items, is never going to work. There will always be a difference.
You'll need to find another way.
You could output a messagebox or update the status line or use a different sizer
, which probably gives you an approximation, of what you're after.
e.g.
Here I use a GridBagSizer
and simply update the label text.
import wx
import time
class Application(wx.Frame):
def __init__(self, *args, **kw) -> None:
super(Application, self).__init__(*args, **kw)
# create a panel in the frame
pnl = wx.Panel(self)
# create some widgets in the panel
self.text_area1 = wx.TextCtrl(pnl, style=wx.TE_MULTILINE | wx.TE_NOHIDESEL)
self.text_area2 = wx.TextCtrl(pnl, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_NOHIDESEL | wx.TE_RICH2)
btn_correct = wx.Button(pnl, label="Correct >>>")
btn_correct.Bind(wx.EVT_BUTTON, self.on_press_correct)
self.btn_copy = wx.Button(pnl, label="Copy")
self.btn_copy.Bind(wx.EVT_BUTTON, self.on_press_copy)
self.label = wx.StaticText(pnl, label=" ")
#self.label.Hide()
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.on_timer, self.timer)
# create a sizer to manage the layout of child widgets
sizer = wx.BoxSizer(wx.VERTICAL)
sub_sizer = wx.GridBagSizer()
sizer.Add(self.text_area1, 1, wx.ALL | wx.EXPAND, 5)
sizer.Add(btn_correct, 0, wx.ALL | wx.CENTER, 5)
sizer.Add(self.text_area2, 1, wx.ALL | wx.EXPAND, 5)
sub_sizer.Add((-1, -1), pos=(0, 0), span=(0, 3), flag=wx.EXPAND, border=5)
sub_sizer.Add(self.btn_copy, pos=(0, 3), flag=wx.ALL | wx.EXPAND, border=5)
sub_sizer.Add(self.label, pos=(0, 4), flag=wx.ALIGN_CENTER, border=5)
sizer.Add(sub_sizer, 0, wx.BOTTOM | wx.CENTER, 5)
pnl.SetSizer(sizer)
self.Show()
def on_press_correct(self, event):
return
def on_press_copy(self, event):
data_obj = wx.TextDataObject()
data_obj.SetText(self.text_area2.GetValue())
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(data_obj)
wx.TheClipboard.Close()
self.btn_copy.Disable()
self.label.SetLabel("Text copied")
#elf.label.GetParent().GetSizer().Layout()
self.timer.StartOnce(3000)
else:
wx.MessageBox("Can't open clipboard", "Error")
def on_timer(self, event):
self.btn_copy.Enable()
#self.label.Show(show=False)
#self.label.GetParent().GetSizer().Layout()
self.label.SetLabel(" ")
app = wx.App(False)
frame = Application(None)
app.MainLoop()
It isn't perfect but it's close.