How can I bind a checkbox to a string such that when the checkbox is checked/unchecked, the value of the string changes? I have this (with CheckAll as my checkbox):
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'BioApp1.xaml')
openDialog = SequenceFileOperations()
self.Sequences = openDialog.Open()
object = MyObjects(self.Sequences)
self.CheckAll.DataContext = object
self.IDLabel.DataContext = object
class MyObjects(object):
def __init__(self, Sequences):
self.CurrentSeq = Sequences[0]
self.ID = self.CurrentSeq.ID
and
<Label Height="28" HorizontalAlignment="Left" Margin="152,221,0,0" VerticalAlignment="Top" Width="98" Name="IDLabel" Content="{Binding Path=ID}"/>
I want that when the checkbox is unchecked, the label should display the sequence ID, but when it is checked, it should simply display “All”. For this I need to change the ID property of CurrentSeq to “All”. How do I do that by data binding? Is there any other way I can do this?
EDIT: I feel really stupid but I just can’t get this to work. I have been trying to follow the suggestion about using getter/setter but I guess I don’t know enough. Before doing anything more complicated, I simply want to make a button disabled when I tick the checkbox and enable it when I uncheck it. This is what I wrote:
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'App1.xaml')
object = BindingClass(self.Check, self.PreviousBtn)
self.PreviousBtn.DataContext = object
class BindingClass(object):
def __init__(self, Check, PreviousBtn):
self.Check = Check
self.PreviousBtn = PreviousBtn
def GetEnabledConverter(self):
if self.CheckAll.IsChecked:
return self.PreviousBtn.IsEnabled
def SetEnabledConverter(self):
if self.CheckAll.IsChecked:
self.PreviousBtn.IsEnabled = False
else:
self.PreviousBtn.IsEnabled = True
EnabledConverter = property(GetEnabledConverter, SetEnabledConverter)
And:
<Button Content="Previous" IsEnabled="{Binding Path=EnabledConverter}" />
Unfortunately there is no error but no effect either. The code does not do anything. Would really appreciate if you could help me out with this.
EDIT2: Using the notify_property, I tried this:
class MyWindow(Window):
def __init__(self):
wpf.LoadComponent(self, 'Test.xaml')
c = Converters(self.check1, self.Button)
self.Button.DataContext = c
class Converters(NotifyPropertyChangedBase):
def __init__(self, check, button):
super(Converters, self).__init__()
self.Check = check
self.Button = button
#notify_property
def ButtonEnabled(self):
return self.Button.IsEnabled
#ButtonEnabled.setter
def ButtonEnabled(self):
if self.Check.IsChecked:
self.Button.IsEnabled = False
else:
self.Button.IsEnabled = True
Still the same result: no effect. I just cannot understand where the problem is.
I would use Converter.
Edit:
You can implement converter in Python:
class BoolToVisibilityConverter(IValueConverter):
def Convert(self, value, targetType, parameter, culture):
return Visibility.Visible if value != val else Visibility.Collapsed
Last time I worked with WPF in IronPython, you could not use it directly in .xaml. I am not sure whether it has improved in 2.7.
Another possibility is to add another property which does the conversion (converted_ID) in its setter/getter. Thinking more about it, I would do rather this, because the code is in one place.
Edit 2:
Make sure, you are using notify_property instead of classic Python property.
Related
It is my first time learning PyQt5.
While I read code related to PyQt5, I have a question some modules.
Is 'isStarted' a variable or in a module?
def __init__(self):
super().__init__()
self.isStarted = False
self.isPaused = False
self.nextMove = None
self.lastShape = Shape.shapeNone
def __init__(self):
super().__init__()
self.isStarted = False
self.isPaused = False
self.nextMove = None
self.lastShape = Shape.shapeNone
Whenever there is an =, rest assured that anything on the left side is a variable. In this case, you are making isStarted variable an attribute of self which is the class in which your code is in. So you can call it from other classes like: print(App.isStarted) (of course, replace App with whatever your class is named.
I need to call a member function when both of my QPushButtons have been pressed. I cannot find a way to keep track of if they have been pressed.
I call a function when either of the buttons are clicked using ...clicked.connect(func) and within that function I have tried to: 1) return a value, 2) update a member variable. Below I have shown how I tried to create and update member variable and use a conditional to see if both variables were true so that I could call my next function.
def __init__(self, parent=None):
super(MorphingApp, self).__init__(parent)
self.setupUi(self)
self.startIm = None
self.endIm = None
self.initialState()
def initialState(self):
self.btn_loadStart.clicked.connect(self.loadImageS)
self.btn_loadEnd.clicked.connect(self.loadImageE)
if(self.startIm is True and self.endIm is True):
self.loadedState()
def initialState(self):
self.startIm = True
def loadImageE(self):
self.endIm = True
My functions of course do things, but I removed parts that were irrelevant. When I run the GUI I am able to load the images but the function that is supposed to be called after both buttons have been pushed is not called. I know this because the state of the GUI is not changing as I intend.
This is my first time posting a question so let me know how to improve :)
Use a simple True/False flag to check if the button has been pressed at least once. Both buttons start with the flag set to False, so we can set that up in the init method.
Then place the code that checks to see if both buttons have been pressed inside the functions connected to them. Finally, simply call the respective "final" function if the check passes.
This is an example using two generic buttons:
def __init__(self, parent=None):
super(MorphingApp, self).__init__(parent)
self.btn_01_pressed = False
self.btn_02_pressed = False
self.set_buttons()
def set_buttons(self):
self.btn_01.clicked.connect(self.check01)
self.btn_02.clicked.connect(self.check02)
def check01(self):
self.btn_01_pressed = True
if self.btn_01_pressed is True and self.btn_02_pressed is True:
self.call_final_function()
def check02(self):
self.btn_02_pressed = True
if self.btn_01_pressed is True and self.btn_02_pressed is True:
self.call_final_function()
def call_final_function(self):
# do something great here
Like in your post I've ommited some parts necessary for the actual code (like creating the QPushButton widgets), but hopefully you get the idea.
def __init__(self, parent=None):
super(MorphingApp, self).__init__(parent)
self.setupUi(self)
self.startIm = False
self.endIm = False
self.btn_loadStart.clicked.connect(self.loadImageS)
self.btn_loadEnd.clicked.connect(self.loadImageE)
def loadImageS(self):
self.startIm = True
if self.startIm and self.endIm:
self.loadedState()
def loadImageE(self):
self.endIm = True
if self.startIm and self.endIm:
self.loadedState()
Uh, okay, friends, now I'm trying to add "export to Excel" feature for every table in my app like this:
...
def update_exportable_tables(self, *window):
"""
Please don't ask why, here 'I know what I'm doing'
"""
if not window:
window = self.window
for obj in window.__dict__:
objname = obj.title().lower()
the_object_itself = window.__dict__[obj]
if isinstance(the_object_itself, (QTableWidget, QTableView)):
the_object_itself.setContextMenuPolicy(Qt.CustomContextMenu)
the_object_itself.customContextMenuRequested.connect(self.TableContextEvent)
def TableContextEvent(self, event):
menu = QMenu()
excelAction = menu.addAction(u"Export to Excel")
excelAction.triggered.connect(self.export)
action = menu.exec_(QCursor.pos())
def export(self):
print 'Here I should do export'
...
Yeah, it works fine, but.... The question is how should I pass the clicked table instance to my export() function?
There are several different ways to solve this. Here's one way:
def update_exportable_tables(self):
for widget in QtGui.qApp.allWidgets():
if isinstance(widget, QTableView):
widget.setContextMenuPolicy(Qt.CustomContextMenu)
widget.customContextMenuRequested.connect(self.showContextMenu)
def showContextMenu(self, pos):
table = self.sender()
pos = table.viewport().mapToGlobal(pos)
menu = QtGui.QMenu()
excelAction = menu.addAction("Export to Excel")
if menu.exec_(pos) is excelAction:
self.export(table)
def export(self, table):
print 'Here I should do export:', table
(NB: QTableWidget is a subclass of QTableView).
Okay, thanks to Eli Bendersky, I googled one way to do it.
if isinstance(the_object_itself, (QTableWidget, QTableView)):
the_object_itself.setContextMenuPolicy(Qt.CustomContextMenu)
tricky = lambda: self.TableContextEvent(the_object_itself)
the_object_itself.customContextMenuRequested.connect(tricky)
...
def TableContextEvent(self, table_instance):
print table_instance
# ^^^^^^^^^^^^^ And yes, we have it!
upd1: It's still wrong, due connecting to only one instance (only last table instance is passed everywhere)
I'm rewriting this post to clarify some things and provide a full class definition for the Virtual List I'm having trouble with. The class is defined like so:
from wx import ListCtrl, LC_REPORT, LC_VIRTUAL, LC_HRULES, LC_VRULES, \
EVT_LIST_COL_CLICK, EVT_LIST_CACHE_HINT, EVT_LIST_COL_RIGHT_CLICK, \
ImageList, IMAGE_LIST_SMALL, Menu, MenuItem, NewId, ITEM_CHECK, Frame, \
EVT_MENU
class VirtualList(ListCtrl):
def __init__(self, parent, datasource = None,
style = LC_REPORT | LC_VIRTUAL | LC_HRULES | LC_VRULES):
ListCtrl.__init__(self, parent, style = style)
self.columns = []
self.il = ImageList(16, 16)
self.Bind(EVT_LIST_CACHE_HINT, self.CheckCache)
self.Bind(EVT_LIST_COL_CLICK, self.OnSort)
if datasource is not None:
self.datasource = datasource
self.Bind(EVT_LIST_COL_RIGHT_CLICK, self.ShowAvailableColumns)
self.datasource.list = self
self.Populate()
def SetDatasource(self, datasource):
self.datasource = datasource
def CheckCache(self, event):
self.datasource.UpdateCache(event.GetCacheFrom(), event.GetCacheTo())
def OnGetItemText(self, item, col):
return self.datasource.GetItem(item, self.columns[col])
def OnGetItemImage(self, item):
return self.datasource.GetImg(item)
def OnSort(self, event):
self.datasource.SortByColumn(self.columns[event.Column])
self.Refresh()
def UpdateCount(self):
self.SetItemCount(self.datasource.GetCount())
def Populate(self):
self.UpdateCount()
self.datasource.MakeImgList(self.il)
self.SetImageList(self.il, IMAGE_LIST_SMALL)
self.ShowColumns()
def ShowColumns(self):
for col, (text, visible) in enumerate(self.datasource.GetColumnHeaders()):
if visible:
self.columns.append(text)
self.InsertColumn(col, text, width = -2)
def Filter(self, filter):
self.datasource.Filter(filter)
self.UpdateCount()
self.Refresh()
def ShowAvailableColumns(self, evt):
colMenu = Menu()
self.id2item = {}
for idx, (text, visible) in enumerate(self.datasource.columns):
id = NewId()
self.id2item[id] = (idx, visible, text)
item = MenuItem(colMenu, id, text, kind = ITEM_CHECK)
colMenu.AppendItem(item)
EVT_MENU(colMenu, id, self.ColumnToggle)
item.Check(visible)
Frame(self, -1).PopupMenu(colMenu)
colMenu.Destroy()
def ColumnToggle(self, evt):
toggled = self.id2item[evt.GetId()]
if toggled[1]:
idx = self.columns.index(toggled[2])
self.datasource.columns[toggled[0]] = (self.datasource.columns[toggled[0]][0], False)
self.DeleteColumn(idx)
self.columns.pop(idx)
else:
self.datasource.columns[toggled[0]] = (self.datasource.columns[toggled[0]][0], True)
idx = self.datasource.GetColumnHeaders().index((toggled[2], True))
self.columns.insert(idx, toggled[2])
self.InsertColumn(idx, toggled[2], width = -2)
self.datasource.SaveColumns()
I've added functions that allow for Column Toggling which facilitate my description of the issue I'm encountering. On the 3rd instance of this class in my application the Column at Index 1 will not display String values. Integer values are displayed properly. If I add print statements to my OnGetItemText method the values show up in my console properly. This behavior is not present in the first two instances of this class, and my class does not contain any type checking code with respect to value display.
It was suggested by someone on the wxPython users' group that I create a standalone sample that demonstrates this issue if I can. I'm working on that, but have not yet had time to create a sample that does not rely on database access. Any suggestions or advice would be most appreciated. I'm tearing my hair out on this one.
Are you building on the wxPython demo code for virtual list controls? There are a couple of bookkeeping things you need to do, like set the ItemCount property.
One comment about your OnGetItemText method: Since there's no other return statement, it will return None if data is None, so your test has no effect.
How about return data or "" instead?
There's a problem with the native object in Windows. If GetImg returns None instead of -1 the list has a problem with column 1 for some reason. That from Robin over on the Google Group post for this issue.
I want to make a checklist with a accordion style in a wxPython widget. I know about checklistbox, but I couldn't find anything in the official docs concerning it. Has anyone done this?
You can use a wx.combo.ComboCtrl which allows any custom popup, and combine this with a wx.CheckListBox.
Here's what is could look like, folded:
and unfolded:
To get this, I started with the ComboCtrl example in the demo, and in the ListCtrlComboPopup list class I replaced ListCtrl with CheckListBox everywhere (and made a few other small changes to make the commands consistent with a CheckListBox control rather than a ListCtrl).
You have to use a wx.PreCheckListBox() for the two part initialization that is required for this.
Here's my implementation. Combine this with a ComboCtrl and you're all set.
import wx
from wx import combo
class checkListComboPopup(combo.ComboPopup):
def __init__(self):
combo.ComboPopup.__init__(self)
self.checklist = wx.PreCheckListBox()
self._value = -1
def Init(self):
self._value = -1
def Create(self, parent):
return self.checklist.Create(parent, 1, wx.Point(0,0), wx.DefaultSize)
def GetControl(self):
return self.checklist
def SetStringValue(self, s):
pass
def GetStringValue(self):
if (self._value >= 0):
return self.checklist.GetItemText(self, self._value)
else:
return wx.EmptyString
def OnMouseMove(self, event):
pass
def GetPreCheckList(self):
return self.checklist
def OnMouseClick(self, event):
pass
Two part creation