Setting the focuspolicy of differents class of widgets - pyqt5

I am currently learning PyQt concepts. Through easy examples, I am trying to play with the tab key to jump from one widget to another.
I manage to disable the focus policy on a PushButton, making it impossible to get the focus on it while pushing Tab. However, with a DialogButton, I do not manage to do so.
I feel managing this policy is possible with every type of widget, but I feel a bit lost with all their specificities.
Here is my current code :
from PyQt5 import QtWidgets, QtCore, QtGui
import sys
class TabWidget(QtWidgets.QDialog): # class to implement dialog box
def __init__(self):
super().__init__()
self.setWindowTitle("Tab Widget App")
tabWidget = QtWidgets.QTabWidget() # creation of the tab widget object
tabWidget.addTab(FirstTab(), "First Tab") # fill with first widget
tabWidget.addTab(SecondTab(), "Second Tab")
tabWidget.addTab(ThirdTab(), "Third Tab")
self.buttonbox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel)
self.buttonbox.setFocusPolicy(QtCore.Qt.NoFocus)
self.buttonbox.accepted.connect(self.accept)
self.buttonbox.rejected.connect(self.reject)
tabWidget.addTab(FourthTab(), "Fourth Tab")
vbox_layout = QtWidgets.QVBoxLayout()
vbox_layout.addWidget(tabWidget)
vbox_layout.addWidget(self.buttonbox)
self.setLayout(vbox_layout)
def keyPressEvent(self, event):
print(event.key())
class FirstTab(QtWidgets.QWidget): # class to implement simple widget
def __init__(self):
super().__init__()
name = QtWidgets.QLabel("Name:")
nameEdit = QtWidgets.QLineEdit()
dob = QtWidgets.QLabel("Birth Date:")
dobEdit = QtWidgets.QLineEdit()
age = QtWidgets.QLabel("Age:")
ageEdit = QtWidgets.QLineEdit()
phone = QtWidgets.QLabel("Phone:")
phoneEdit = QtWidgets.QLineEdit()
vbox_layout = QtWidgets.QVBoxLayout()
vbox_layout.addWidget(name)
vbox_layout.addWidget(nameEdit)
vbox_layout.addWidget(dob)
vbox_layout.addWidget(dobEdit)
vbox_layout.addWidget(age)
vbox_layout.addWidget(ageEdit)
vbox_layout.addWidget(phone)
vbox_layout.addWidget(phoneEdit)
self.setLayout(vbox_layout)
class SecondTab(QtWidgets.QWidget): # class to implement simple widget
def __init__(self):
super().__init__()
selectGroup = QtWidgets.QGroupBox("Select Operating Systems")
combo = QtWidgets.QComboBox()
list = {"Windows", "Mac", "Linux"}
combo.addItems(list)
selectLayout = QtWidgets.QVBoxLayout()
selectLayout.addWidget(combo)
selectGroup.setLayout(selectLayout)
checkGroup = QtWidgets.QGroupBox("Which Operation System Do You Like?")
windows = QtWidgets.QCheckBox("Windows")
mac = QtWidgets.QCheckBox("Mac")
linux = QtWidgets.QCheckBox("Linux")
checklayout = QtWidgets.QVBoxLayout()
checklayout.addWidget(windows)
checklayout.addWidget(mac)
checklayout.addWidget(linux)
checkGroup.setLayout(checklayout)
mainlayout = QtWidgets.QVBoxLayout()
mainlayout.addWidget(selectGroup)
mainlayout.addWidget(checkGroup)
self.setLayout(mainlayout)
class ThirdTab(QtWidgets.QWidget):
def __init__(self):
super().__init__()
label = QtWidgets.QLabel("Terms And Conditions")
listwidget = QtWidgets.QListWidget()
list = []
for i in range(1,20):
list.append("This Is Terms And Conditions")
listwidget.insertItems(0, list)
checkbox = QtWidgets.QCheckBox("Agree The Terms And Condition")
layout = QtWidgets.QVBoxLayout()
layout.addWidget(label)
layout.addWidget(listwidget)
layout.addWidget(checkbox)
self.setLayout(layout)
class FourthTab(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.groupBox = QtWidgets.QGroupBox("Issue", objectName = 'groupBox')
self.grid_layout = QtWidgets.QGridLayout(self.groupBox)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
self.widgetOne = QtWidgets.QTextEdit(self.groupBox, tabChangesFocus = True)
self.widgetOne_label = QtWidgets.QLabel("widgetOne")
self.widgetOne.setObjectName("WidgetOne")
self.grid_layout.addWidget(self.widgetOne, 1, 0, 1, 1)
self.grid_layout.addWidget(self.widgetOne_label, 0, 0, 1, 1)
sizePolicy.setHeightForWidth(self.widgetOne.sizePolicy().hasHeightForWidth())
self.grid_layout.addWidget
self.widgetTwo = QtWidgets.QTextEdit(self.groupBox, tabChangesFocus = True)
self.widgetTwo_label = QtWidgets.QLabel("widgetTwo")
self.widgetTwo.setObjectName("widgetTwo")
self.grid_layout.addWidget(self.widgetTwo, 1, 1, 1, 1)
self.grid_layout.addWidget(self.widgetTwo_label, 0, 1, 1, 1)
sizePolicy.setHeightForWidth(self.widgetTwo.sizePolicy().hasHeightForWidth())
self.grid_layout.addWidget
self.widgetThree = QtWidgets.QTextEdit(self.groupBox, tabChangesFocus = True)
self.widgetThree_label = QtWidgets.QLabel("widgetThree")
self.widgetThree.setObjectName("widgetThree")
self.grid_layout.addWidget(self.widgetThree, 4, 0, 1, 1)
self.grid_layout.addWidget(self.widgetThree_label, 3, 0, 1, 1)
sizePolicy.setHeightForWidth(self.widgetThree.sizePolicy().hasHeightForWidth())
self.grid_layout.addWidget
self.widgetFour = QtWidgets.QTextEdit(self.groupBox, tabChangesFocus = True)
self.widgetFour_label = QtWidgets.QLabel("widgetFour")
self.widgetFour.setObjectName("WidgetFour")
self.grid_layout.addWidget(self.widgetFour, 4, 1, 1, 1)
self.grid_layout.addWidget(self.widgetFour_label, 3, 1, 1, 1)
sizePolicy.setHeightForWidth(self.widgetFour.sizePolicy().hasHeightForWidth())
self.grid_layout.addWidget
v_layout = QtWidgets.QVBoxLayout()
v_layout.addWidget(self.groupBox)
self.setLayout(v_layout)
self.setTabOrder(self.widgetOne, self.widgetTwo)
self.setTabOrder(self.widgetTwo, self.widgetThree)
self.setTabOrder(self.widgetThree, self.widgetFour)
self.setTabOrder(self.widgetFour, self.widgetOne)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
tabwidget = TabWidget()
tabwidget.show()
sys.exit(app.exec_())
The involved button is my "buttonbox" of type QDialogButton. I have set the focus policy to NoFocus. But when I launch the script and use the tab key in FourthTab, the focus still goes on OK / Cancel.
Are there some restrictions about this option? Or is there something I am missing?

The focus policy is not propagated to the children.
When you set the focus policy on the button box, its children (the buttons) still have their default policy (which is StrongFocus).
If you want to disable that for all buttons, you need to do it explicitly, for instance:
self.buttonbox.button(self.buttonbox.Ok).setFocusPolicy(QtCore.Qt.NoFocus)
Or, for any button:
for button in self.buttonbox.findChildren(QtWidgets.QAbstractButton):
button.setFocusPolicy(QtCore.Qt.NoFocus)
Note that the keyPressEvent is only received by a parent if none of its children has handled it, so if you're trying to capture the Tab you need to install an event filter on the whole QApplication instead, otherwise it's still possible that some widget will capture and accept it, thus preventing you to receive it.

Related

Tkinter: How can I check if any of the widgets of a specific frame have changed?

What is the best way to check if any widget (or variable linked to it) of a given frame(frm1) has changed and take an action. For example activate a button.
I would like that when something was typed in the entries or changed the combobox or checkbox, the 'changed_content' function would be executed
from tkinter import *
from tkinter import ttk
from tkinter.messagebox import showinfo
class Defaultframe(Tk):
def __init__(self):
Tk.__init__(self)
self.geometry('500x300')
self.title('Tkinter')
self.text1 = StringVar()
self.text2 = StringVar()
self.text3 = StringVar()
self.var1 = IntVar()
self.var2 = IntVar()
self.set_widgets()
return
def changed_content(self):
showinfo('Information', 'The content has been changed')
self.btn2.configure(state='normal')
return
def set_widgets(self):
#Frame1
self.frm1 = ttk.Frame(self).pack(side=TOP)
self.lbl = ttk.Label(self.frm1, text='Text1').pack(pady=5)
self.ent1 = ttk.Entry(self.frm1, textvariable=self.text1).pack(pady=5)
self.lbl = ttk.Label(self.frm1, text='Text2').pack(pady=5)
self.my_ent = ttk.Entry(self.frm1, textvariable=self.text2).pack(pady=5)
self.cbb = ttk.Combobox(self.frm1,
values=[0, 30, 60, 90, 120, 150, 180],
state='readonly',
textvariable=self.var2)
self.cbb.pack(pady=5)
self.cbb.current(3)
self.ckb = ttk.Checkbutton(self.frm1, text='Hello', variable=self.var1, onvalue=1, offvalue=0).pack(pady=5)
#---
#Frame2
self.frm2 = ttk.Frame(self).pack(side=BOTTOM, fill=X)
ttk.Separator(self.frm2, orient=HORIZONTAL).pack(side=TOP, expand=1, fill=X)
self.my_ent3 = ttk.Entry(self.frm2, textvariable=self.text3).pack(side=LEFT, padx=1)
self.btn1 = ttk.Button(self.frm2, text='Cancel').pack(side=RIGHT, padx=1)
self.btn2 = ttk.Button(self.frm2, text='Save')
self.btn2.pack(side=RIGHT, padx=1)
self.btn2.configure(state=DISABLED)
#---
if __name__== '__main__':
app = Defaultframe()
app.mainloop()
Solving for any widget is tough - you'll have to write code specifically for a canvas or a scrollbar or any other widget that isn't associated with a tkinter variable.
For widgets that are associated with a tkinter variable you can apply a trace that will call a function whenever the value changes.
In your code it might look something like this:
class Defaultframe(Tk):
def __init__(self):
...
self._watch_variables(self.text1, self.text2, self.text3, self.var1, self.var2)
def _watch_variables(self, *vars):
for var in vars:
var.trace_add("write", self._handle_trace)
def _handle_trace(self, *args):
self.changed_content()

How to modify drop event in QListView

I have a QListView where items can be reordered with drag-and-drop by setting dragDropMode to DragDrop and defaultDropAction to MoveAction. How can I intercept the drop event, to find out what is trying to be moved where in relation to the rest of the list, so that I can cancel this action under certain conditions? E.g. I want to forbid moving some items behind other.
You can access the indexes and items involved in the dropEvent and setDropAction to Qt.IgnoreAction to cancel the drop depending on your criteria. Since you weren't specific, for this demonstration I just created one item that stays at the bottom.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class List(QListView):
def dropEvent(self, event):
i = self.selectedIndexes()[0]
j = self.indexAt(event.pos())
# To access the items involved
source = self.model().itemFromIndex(i)
target = self.model().itemFromIndex(j)
bottom = (self.model().rowCount() - 1, -1)
if i.row() in bottom or j.row() in bottom:
event.setDropAction(Qt.IgnoreAction)
else:
super().dropEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = QWidget()
lv = List()
lv.setDragDropMode(QAbstractItemView.DragDrop)
lv.setDefaultDropAction(Qt.MoveAction)
model = QStandardItemModel(5, 1)
for i in range(4):
item = QStandardItem(f'Item {i + 1}')
item.setFlags(item.flags() & ~Qt.ItemIsDropEnabled)
model.setItem(i, 0, item)
item = QStandardItem('I stay at the bottom ._.')
model.setItem(4, 0, item)
lv.setModel(model)
vbox = QVBoxLayout(window)
vbox.addWidget(lv)
window.show()
sys.exit(app.exec_())

Pyqt5 synchronization between two tabwidget which are in different window

I want to make new window by double click tabwidget.
and copy tabwidget's (child which is tablewidget) to new window.
and finally, changing item of new window's tablewidget needs to change mainwindow's tablewidget.
would it be possible?
I have seen this, that answer does copy tabwidget to new window
but remove mainwindow tabwidget.
here is I worked so far.
I managed to make new dialog by double click, but other things.. I dont' have any clues. can anyone can help?
#!/usr/bin/python
# -*- coding: utf8 -*-
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class DetachableTabWidget(QTabWidget):
def __init__(self, parent=None):
QTabWidget.__init__(self)
self.tabBar = self.TabBar(self)
self.tabBar.onDetachTabSignal.connect(self.detachTab)
self.setTabBar(self.tabBar)
print("DetachableTabWidget")
#pyqtSlot(int, QPoint)
def detachTab(self, index, point):
print("detachTab")
all_list = []
list1 = []
list2 = []
name = self.tabText(index)
icon = self.tabIcon(index)
if icon.isNull():
icon = self.window().windowIcon()
contentWidget = self.widget(index)
contentWidgetRect = contentWidget.frameGeometry()
tablewidgetA = contentWidget.findChild(QTableWidget)
for i in range(tablewidgetA.rowCount()):
list1.append(tablewidgetA.item(i, 0).text())
list2.append(tablewidgetA.item(i, 1).text())
all_list.append(list1)
all_list.append(list2)
detachedTab = self.DetachedTab(all_list)
detachedTab.setWindowModality(Qt.NonModal)
detachedTab.setWindowTitle(name)
detachedTab.setWindowIcon(icon)
detachedTab.setObjectName(name)
detachedTab.setGeometry(contentWidgetRect)
detachedTab.move(point)
detachedTab.exec_()
class DetachedTab(QDialog) :
onCloseSignal = pyqtSignal(QWidget,type(''), QIcon)
# def __init__(self, contentWidget, parent=None):
def __init__(self, all_list, parent=None) :
print("DetachedTab")
super().__init__()
layout = QVBoxLayout(self)
table = QTableWidget()
table.setColumnCount(len(all_list))
table.setRowCount(len(all_list[0]))
for col in range(len(all_list)) :
for row in range(len(all_list[col])) :
item = QTableWidgetItem(all_list[col][row])
table.setItem(row, col, item)
layout.addWidget(table)
table.show()
class TabBar(QTabBar):
onDetachTabSignal = pyqtSignal(int, QPoint)
onMoveTabSignal = pyqtSignal(int, int)
def __init__(self, parent=None):
QTabBar.__init__(self, parent)
self.setAcceptDrops(True)
self.setElideMode(Qt.ElideRight)
self.setSelectionBehaviorOnRemove(QTabBar.SelectLeftTab)
self.dragStartPos = QPoint()
self.dragDropedPos = QPoint()
self.mouseCursor = QCursor()
self.dragInitiated = False
def mouseDoubleClickEvent(self, event) :
event.accept()
self.onDetachTabSignal.emit(self.tabAt(event.pos()), self.mouseCursor.pos())
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.centralTabs = DetachableTabWidget()
self.setCentralWidget(self.centralTabs)
self.setFixedWidth(600)
self.setFixedHeight(600)
#tab 1
self.tab_1 = QWidget()
self.centralTabs.addTab(self.tab_1,"Tab 1")
vbox = QVBoxLayout()
Table = QTableWidget(2, 2)
vbox.addWidget(Table)
item = QTableWidgetItem("table 1 content")
Table.setItem( 0, 0, item)
item = QTableWidgetItem("table 2 content")
Table.setItem( 0, 1, item)
item = QTableWidgetItem("table 3 content")
Table.setItem( 1, 0, item)
item = QTableWidgetItem("table 4 content")
Table.setItem( 1, 1, item)
vbox.setAlignment(Qt.AlignTop)
self.tab_1.setLayout(vbox)
#tab 2
self.tab_2 = QWidget()
self.centralTabs.addTab(self.tab_2,"Tab 2")
vbox = QVBoxLayout()
Table = QTableWidget(2, 2)
item = QTableWidgetItem("table 2 content")
Table.setItem( 0, 0, item)
item = QTableWidgetItem("table 3 content")
Table.setItem( 0, 1, item)
item = QTableWidgetItem("table 4 content")
Table.setItem( 1, 0, item)
item = QTableWidgetItem("table 5 content")
Table.setItem( 1, 1, item)
vbox.addWidget(Table)
vbox.setAlignment(Qt.AlignTop)
self.tab_2.setLayout(vbox)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
ex.show()
sys.exit(app.exec_( ))
If you want to synchronize data between item views, you have to use a common model. Since you're using a QTableWidget (which has an internal, private model, and a higher level item view) you can create a new window using a QTableView instead, and set its model to the source. In that case, you don't need to "copy" row/column/data, you only need to use the source model.
Here's a modified version of your script:
class DetachableTabWidget(QTabWidget):
# ...
#pyqtSlot(int, QPoint)
def detachTab(self, index, point):
print("detachTab")
name = self.tabText(index)
icon = self.tabIcon(index)
if icon.isNull():
icon = self.window().windowIcon()
contentWidget = self.widget(index)
contentWidgetRect = contentWidget.frameGeometry()
tablewidgetA = contentWidget.findChild(QTableWidget)
detachedTab = self.DetachedTab(tablewidgetA.model())
detachedTab.setWindowTitle(name)
detachedTab.setWindowIcon(icon)
detachedTab.setObjectName(name)
detachedTab.setGeometry(contentWidgetRect)
detachedTab.move(point)
detachedTab.exec_()
class DetachedTab(QDialog) :
onCloseSignal = pyqtSignal(QWidget,type(''), QIcon)
def __init__(self, model, parent=None) :
print("DetachedTab")
super().__init__()
layout = QVBoxLayout(self)
table = QTableView()
table.setModel(model)
layout.addWidget(table)
table.show()
With this code you can modify the "child" window table data, and it will always synchronize the source table widget.

How to create a dropdown from a gtk.Entry's icon?

I have a gtk.Entry with an icon after the text, intending to be a text search field:
What I'm trying to do is to display a dropdown (i.e. a gtk.ComboBox) when the user clicks on the icon, to choose the type of search. A mock of that feature would be:
I have tried several things without any success. For example, trying to pack an empty gtk.ComboBox only showing an arrow right after the Entry, and stuffing it only on icon-press, which creates the illusion, but it has two drawbacks: a) when I stuff the ComboBox, the toolbar grows, and b) when I clear() the ListStore, the ComboBox retains its width and leaves an ugly grey box.
At this point I guess that I need to create a CellRenderer on icon-press that pops down the icon of the Entry, and I tried without a lot of success to understand the code of gtk.ComboBoxEntry (in gtkcomboboxentry.c), but as far as I understood it uses a vertical Container on the whole piece together with a CellRenderer.
Also GTK+3 doesn't have any ideas on this respect.
Any ideas, or some guidance in how to create this in PyGTK?
I was looking for something similar, so I came up with the code below. I haven't really worried about the aesthetics. I did pass a list of tuples to the MyPopup class, with the idea of passing handlers for each of the menu items in the dropdown. Note that the item.show() is necessary, even though there is a show_all():
from gi.repository import Gtk
class MyPopup(Gtk.MenuButton):
def __init__(self, btndefs):
super(MyPopup, self).__init__()
self.menu = Gtk.Menu()
self.set_popup(self.menu)
#self.set_label(">")
self.set_direction(Gtk.ArrowType.RIGHT)
for btndef in btndefs:
item = Gtk.MenuItem()
item.set_label(btndef[0])
item.show()
self.menu.append(item)
class MainWindow(Gtk.Window):
def __init__(self):
super(MainWindow, self).__init__()
self.set_size_request(100, -1)
self.connect("destroy", lambda x: Gtk.main_quit())
self.hbox = Gtk.Box(orientation = Gtk.Orientation.HORIZONTAL)
self.entry = Gtk.Entry()
self.popup = MyPopup( (("String",),
("String no case",),
("Hexadecimal",),
("Regexp",)) )
self.hbox.pack_start(self.entry, True, True, 0)
self.hbox.pack_start(self.popup, False, True, 0)
self.add(self.hbox)
self.show_all()
def run(self):
Gtk.main()
def main():
mw = MainWindow()
mw.run()
return 0
if __name__ == '__main__':
main()
yup its year late, but lets not make next person stumbled here to be sad like me.
this is the example using Gtk.Menu() popup, you can also similar feat. with Gtk.Popover()
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk
opts = {
'hex' : "system-run-symbolic",
'regex' : "font-select-symbolic",
'string' : "font-x-generic-symbolic",
'no-case' : "tools-check-spelling-symbolic",
}
def make_menu(entry, opts):
menu = Gtk.Menu()
for label, icon in opts.items():
item = Gtk.MenuItem()
item.set_label(label)
item.connect(
"activate",
lambda w: entry.set_icon_from_icon_name(0, opts[w.get_label()])
)
menu.append(item)
# NOTE you can use Gtk.ImageMenuItem to add image but its
# Deprecated since version 3.10
menu.show_all()
return menu
def on_icon_release(widget, pos, event):
menu = make_menu(widget, opts)
menu.popup(
parent_menu_shell = None,
parent_menu_item = None,
func = None,
data = None,
button = Gdk.BUTTON_PRIMARY,
activate_time = event.get_time()
)
def make_entry():
entry = Gtk.Entry()
entry.set_icon_from_icon_name(0, 'action-unavailable-symbolic')
entry.set_icon_from_icon_name(1, 'fonts')
entry.set_icon_sensitive(1, True)
entry.set_icon_activatable(1, True)
entry.connect("icon-release", on_icon_release)
return entry
root = Gtk.Window()
root.add(make_entry())
root.show_all()
Gtk.main()

ScrolledPanel not resizing after DestroyChildren

I got this code from a topic on Stackoverflow ScrolledPanel inside Panel not sizing. It works well for me. However I want to destroy all children of the scrolled_panel then recreate its new children. So I modify the code like this:
import wx
import wx.lib.scrolledpanel as scrolled
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial", size=(200,500))
self.n = 13
# Add a panel so it looks the correct on all platforms
self.panel = wx.Panel(self, wx.ID_ANY)
# --------------------
# Scrolled panel stuff
self.scrolled_panel = scrolled.ScrolledPanel(self.panel, -1,
style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="panel1")
self.scrolled_panel.SetAutoLayout(1)
self.scrolled_panel.SetupScrolling()
words = "A Quick Brown Insane Fox Jumped Over the Fence and Ziplined to Cover".split()
self.spSizer = wx.BoxSizer(wx.VERTICAL)
for word in words:
text = wx.TextCtrl(self.scrolled_panel, value=word)
self.spSizer.Add(text)
self.scrolled_panel.SetSizer(self.spSizer)
# --------------------
btn = wx.Button(self.panel, label="Add Widget")
btn.Bind(wx.EVT_BUTTON, self.onAdd)
panelSizer = wx.BoxSizer(wx.VERTICAL)
panelSizer.AddSpacer(50)
panelSizer.Add(self.scrolled_panel, 1, wx.EXPAND)
panelSizer.Add(btn)
self.panel.SetSizer(panelSizer)
#----------------------------------------------------------------------
def onAdd(self, event):
""""""
print "in onAdd"
self.n += 1
self.scrolled_panel.DestroyChildren()
for i in range(self.n):
new_text = wx.TextCtrl(self.scrolled_panel, value="New Text %s" % i)
self.spSizer.Add(new_text)
#new_text = wx.TextCtrl(self.scrolled_panel, value="New Text")
#self.spSizer.Add(new_text)
self.scrolled_panel.Layout()
self.scrolled_panel.SetupScrolling()
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()
Now, even when I create the children more than the panel's size can show, I don't see the scroll bar as the original code. Can any one help me with this? Thanks ahead!!!
I solved this problem by adding testpanel to add scrolledPanel in it. Whennever onAdd() is call, after destroying all of testpanel's children, everything under the testpanel even the sizer have to be re-created and re-setup.
I've tried to do like that without the testpanel, I still could scroll by using my mouse, but didn't see the scrollbar, I don't know why. This is my new code:
import wx
import wx.lib.scrolledpanel as scrolled
########################################################################
class MyForm(wx.Frame):
#----------------------------------------------------------------------
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Tutorial", size=(200,500))
self.n =17
# Add a panel so it looks the correct on all platforms
self.panel = wx.Panel(self, wx.ID_ANY)
panelSizer = wx.BoxSizer(wx.VERTICAL)
panelSizer.AddSpacer(50)
# add a panel
self.testpanel = wx.Panel(self.panel, wx.ID_ANY)
#self.testpanel.SetSizer(self.testpanelSizer)
panelSizer.Add(self.testpanel, 1, wx.EXPAND)
self.onAdd()
btn = wx.Button(self.panel, label="Add Widget")
btn.Bind(wx.EVT_BUTTON, self.onAdd)
panelSizer.Add(btn)
self.panel.SetSizer(panelSizer)
#----------------------------------------------------------------------
def onAdd(self, event=None):
self.n +=1
self.testpanel.DestroyChildren()
testpanelSizer = wx.BoxSizer(wx.VERTICAL)
scrolled_panel = scrolled.ScrolledPanel(self.testpanel, -1,
style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="panel1")
scrolled_panel.SetAutoLayout(1)
scrolled_panel.SetupScrolling()
spSizer = wx.BoxSizer(wx.VERTICAL)
for i in range(self.n):
new_text = wx.TextCtrl(scrolled_panel, value="New Text %s" % i)
spSizer.Add(new_text)
scrolled_panel.SetSizer(spSizer)
testpanelSizer.Add(scrolled_panel, 1, wx.EXPAND)
self.testpanel.SetSizer(testpanelSizer)
self.testpanel.Layout()
# Run the program
if __name__ == "__main__":
app = wx.App(False)
frame = MyForm().Show()
app.MainLoop()