I'm trying to create a UI with 3 columns - when you select an item in the left column, the select item is passed to a function, and it returns the items for the middle column (and of course same for selecting items in the middle column)
Should be simple, but I can't find any easy way to do this..
I first tried QColumnView, as it seemed perfect.. however implementing the QAbstractItemModel seems excessively complicated, and I couldn't find any useful examples of this.
Next, since there is a fixed number of levels, I made three QListView, and modified this example QAbstractListModel
..however there seemed to be no useful signal I could use to trigger the updating of the other levels of the hierarchy. According to the PyQT docs, QListView only has the "indexesMoved" signal. There is also "clicked" and "pressed", however these didn't trigger when changing items with the keyboard
The last options is QListWidget, which would work as it has the required signals (itemChanged etc), but the way list items are created is a bit tedious (making QListWidgetItem with the parent set to the QListWidget instance)
Edit: QListWidget does pretty much what I need:
self.first_column = QListWidget()
self.first_column.itemSelectionChanged.connect(self.update_second_column)
Any QAbastractItemView has a QItemSelectionModel accessible via the selectionModel method.
The QItemSelectionModel has signals that may help you:
currentChanged ( const QModelIndex & current, const QModelIndex & previous )
currentColumnChanged ( const QModelIndex & current, const QModelIndex & previous )
currentRowChanged ( const QModelIndex & current, const QModelIndex & previous )
selectionChanged ( const QItemSelection & selected, const QItemSelection & deselected )
Hope it helps.
QListView inherits from QAbstractItemView (I think you knew this), so it gets a few signals, hopefully one (or a few) of them works for you.
This is working for me (connect signals when initializing your QMainWindow or main QWidget, as in the SaltyCrane example):
connect(your_list_view, SIGNAL("clicked(const QModelIndex&)"), handler_slot)
...
def handler_slot(idx):
#idx is a QModelIndex
#QModelIndex.data() returns a QVariant, Qt4's generic data container
celldata = idx.data()
#Choose the proper datatype to ask the QVariant for (e.g. QVariant.toInt())
actualvalue = celldata.toInt()
#QVariant.toInt() happens to return a tuple
print actualvalue[0]
Depending on the type of data in your model, you'll want to choose the right data type to ask QVariant for.
The sneaky part here is getting the QListView to tell you which cell was clicked (i.e. using clicked(const QModelIndex&) vs clicked()). I think I spent some time looking at the C++ documentation for Qt4 before I realized you could get more out of the signals.
From here, I would have the handler_slot() call a setData() method on the model for your second QListView (using data generated by the function you originally planned to use).
I'd be glad to elaborate if I haven't quite answered your question.
Edit: Working with arrow keys
Hmm, it seems weird that there isn't a default QListView signal for arrow movement, but we can make our own.
(This almost seems out-of-style for Qt4's signals and slots modus operandi)
QListView reimplements a method keyPressEvent(self, QKeyEvent) which acts as a callback function when certain keys are pressed. You can read more. We can use this to grab the keyevent(s) that we want, and emit our own signal.
class ArrowableListView(QListView):
def keyPressEvent(self, keyevent):
#Maintain original functionality by calling QListView's version
QListView.keyPressEvent(self, keyevent)
#QListView.selectedIndexes returns a list of selected cells, I'm just taking the first one here
idx = self.selectedIndexes()[0]
#We'll emit a signal that you can connect to your custom handler
self.emit(SIGNAL("my_signal"), idx)
Once a keypress occurs, we ask the QListView what the selected indices (!) are. Of course, you can choose to filter out certain keys and choose whether to handle multiple selected cells (I think you can set a selection mode where this isn't possible, see QListView documentation).
Now that we have the selected indices (list of QModelIndex), we pass the first one (a QModelIndex) along with our signal. Because we're defining this signal in python, we don't have to set a function prototype; I have no idea if this is bad style.
Now all you have to do is connect the signal to a handler:
self.connect(your_list_view, SIGNAL("my_signal"), handler_slot)
and write your handler.
I hope this isn't too nasty of a workaround.
Related
I'm trying allow a user to sort the grid by a column who's value is derived:
grid.addColumn(Category::getPath).setHeader("Path");
grid.addColumn(category -> getCount(category))
.setHeader("Packages")
.setComparator((a,b) -> orderByCount(a, b));
private int orderByCount(Category a, Category b)
{
Long acount = daoCategoryPackage.getCount(CategoryPackage_.category, a);
Long bcount = daoCategoryPackage.getCount(CategoryPackage_.category, b);
return acount.compareTo(bcount);
}
The grid shows the 'sort' icon in the header and I can click the icon and it changes state (up arrow, down arrow, both arrows).
If I trace the code I can see that the grid attempts a sort as 'Grid:setSortOrder' is called and the columnKey in GridSortOrder is correct (col1).
However the orderByCount method is never called.
It feels like I need to add some other setting to the grid but the documentation makes no suggestion and looking at the api I can see anything obvious.
It's not possible to know without seeing more of the code, but the problem is likely that you're using a lazy-loading dataprovider, which can't handle a comparator provided like that. If you look at the method's JavaDoc, you'll see:
Sets a comparator to use with in-memory sorting with this column. Sorting with a back-end is done using setSortProperty(String...).
After reading the documentation about the second parameter in knockout applyBindins, I understand the reason behind it:
Optionally, you can pass a second parameter to define which part of
the document you want to search for data-bind attributes. For example,
ko.applyBindings(myViewModel,
document.getElementById('someElementId')). This restricts the
activation to the element with ID someElementId and its descendants,
which is useful if you want to have multiple view models and associate
each with a different region of the page.
But I have not seen anything about performance. My thoughts (which are based on nothing) are that it makes sense that ko bindings will work faster if to restring the binding not to the whole document, but to a small part of it.
So does it make sense to use ko.applyBindings(myViewModel, $('#someElementId')[0]) without having multiple view models just for the sake of performance. (I heard about Mr. Knuth, so it would be nice to refrain from optimization citation).
applyBindings is a thin wrapper over applyBindingsToNodeAndDescendantsInternal (which is where ALL the magic happens) and if you don't supply a node it uses window.document.body
There is no difference between calling applyBindings(viewModel) and applyBindings(viewMode,rootNode) unless you have a very large DOM and only want to bind a small fraction. In this case use the second parameter and Knockout will have a lot less to scan on the initial setup.
Once the bindings are in place they are reacting locally to observable changes, unlike a framework like AngularJS that can potential scan the entire DOM for changes. The root node is irrelevant at this point.
ko.applyBindings = function (viewModel, rootNode) {
if (rootNode && (rootNode.nodeType !== 1) && (rootNode.nodeType !== 8))
throw new Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");
rootNode = rootNode || window.document.body; // Make "rootNode" parameter optional
applyBindingsToNodeAndDescendantsInternal(viewModel, rootNode, true);
};
If I add attributes to an event, I know I can then use the event name like a function...
BOOST_MSM_EUML_EVENT_WITH_ATTRIBUTES(*someEvent*, *someAttributeList*)
someStateMachine.process_event(
someEvent (
valueOfSomeAttribute1, // sets the attribute value here
valueOfSomeAttribute2))
and that inside an action I can this back by writing
evt.get_attribute(someAttribute1); // retrieve the attribute value
Now, if I set an attribute for an entire machine, like so:
BOOST_MSM_EUML_DECLARE_STATE_MACHINE((transition_table,
init_ << initState,
Entry_Action,
Exit_Action,
attributes_ << someAttribute1 << someAttribute2,
configure_<< someConfigurationStuff ),
newStateMachineType)
How do I go about setting a value for someAttribute1?
Same question for states:
BOOST_MSM_EUML_STATE(
(someEntryAction,
someExitAction,
attributes_ << someAttribute1,
configure_<< someConfigurationStuff)
,newStateName)
How do I go about setting a value for someAttribute1?
Finally,
Is there a way to change the attributes after the object is created?
For instance, I'd like to have an attribute for the state machine, and in one of my states, remember some piece of information that I can store in the state machine. (In this case, I want to store a socket.)
Thanks.
How do I go about setting a value for someAttribute1?
You can:
change the reference you just got (get_attribute returns a reference): ++evt.get_attribute(someAttribute1).
use the functors to write the attribute in your table directly. For example, following action is possible: /++fsm_(someAttribute1)
For states, you can do the same. And for state machines, well, ditto.
Again, you can either use the Fsm template parameter in your actions, or the functors (fsm_, event_, etc.)
You can find good example of all in the examples or tests (for example test/CompositeEuml.cpp or test/AnonymousEuml.cpp).
HTH,
Christophe
I am quite new to Qt and am in a situation where I want to use a model for my needs:
I have a dynamic number of instances of a subclass that need to be handled differently (different UI controls for each if it is selected). I want to get a list view where I can add new elements or delete old ones, as well as disabling/enabling existing ones.
Of course I want to rewrite as least of the code as possible, so I thought of utilizing the Listwidget and a ListModel to give some controls to the user. But how to link these (or better the items) to instances of the classes?
Do you know any tutorials on this?
I already looked in QtDemo and Google but I do not know the right words to search for
so I had no good results.
Basically what I think I need is a model item that accepts Collider* for its data.
But when I plug this into QStandardItem.setData() it says error: ‘QVariant::QVariant(void*)’ is private
So I found the solution to this problem.
As QStandardItems are capable of storing QVariants as data I wanted to store a pointer to my data in a QVariant. To achieve this I had to use Q_DECLARE_METATYPE(MyType*).
With this I was able to
MyType *MyInstance = new MyType;
QVariant data;
data.setValue(MyInstance);
QStandardItem *item = new QStandardItem("My Item");
item->setData(data);
standardModel->appendRow(item);
And the best is you can add as many types you want and let QVariant do the work to decide if it contains the type you wanted:
if(v.canConvert<MyType*>())
//Yes it is MyType
else if( v.canConvert<MyOtherType*>())
//Oh it is the other one
So finally this only requires to declare the meta type so you do not have to subclass any items.
Also you should read on the limitations of this here:
Q_DECLARE_METATYPE
qRegisterMetaType
Does this page answer your questions? There's an example of deriving a StringListModel item that you might be able to use as a template
If I have a method that hides a button, I would probably call it HideButton
If I have a method that shows a button, I would probably call it ShowButton
But what do you guys call a ShowIfThisHideIfThat style method?
Possible Choices:
TestForButtonVisibility (this kind of sounds like it will return true/false but not actually do the work)
TestButton
ShowHideButton (style I'm currently using)
Been at this a number of years and still don't have a style that I like for these types of methods. I'm working mostly in C# and a little Java, Ruby, and F#. What do you use for method names in this regard?
// example of the style of method
public void ShouldIShowOrHideButton()
{
Button.Visible = ((chkSomeSetting.Checked) && (DateTime.Now.Day < 8));
}
How about updateButtonVisibilty()?
Might be overengineering, but the reason you may have problems because it's doing two things. So making sure you only have a function doing a single thing, howabout a method to determine if the button should be shown or not (takes parameters, returns bool), then set the value of the button directly.
Button.Visibilty = DetermineIfButtonShouldBeShow(...);
My preference has been to keep toggle methods rather than separate methods for hide/show.
ToggleButtonVisibility()
This allows you to put your testing code in there and the expected result/output would be a properly visible/invisible button.
Edit: Toggle is a personal preference that stems from a partial background in working with binary gates, architecture, etc where a toggle may go through several separate gates before reaching an end state. The word itself could be changed to anything else such as Update, Determine, Finalize, or even Steve. It really boils down to what makes sense to you and what your standard is.
Edit: Now your question is edited to include the example
// example of the style of method
public void ShouldIShowOrHideButton()
{
Button.Visible = ((chkSomeSetting.Checked) && (DateTime.Now.Day < 8));
}
My answer is neither. I would do two things:
Move the Button.Visible part outside the function, so the function just computes the logic and returns bool.
Name the function according to its internal logic not according to whether it is for a button or not. So if your function checks for a wedding day it would be called IsWeddingDay, if it checks for a monthly meeting it would be IsMonthlyMeeting.
The code would be
Button.Visible = IsMonthlyMeeting()
and the logic can be subsequently used to control any other widgets if needed.
Old Answer:
You probably need to explain more what ShowIfThisHideIfThat does.
If it depends on one condition, like:
if (condition)
ShowBotton()
else
HideButton()
then I would use
Button.SetVisibility(condition)
as per Lazarenko's comment above, or if the language has properties:
Button.Visible = condition
If you have two conditions like what ShowIfThisHideIfThat seems to imply, equivalent to:
if (cond1)
ShowButton()
else if (cond2)
HideButton()
else
LeaveButtonAsItIs()
then the logic in my opinion is complicated and I wouldn't use one function. Sure, the code is equivalent to
Button.Visible = cond1 || (!cond2 && Button.Visible)
but you lose the understandability.
I would use one of these:
setXVisibility
refreshX or refreshXStatus
How about using SetButtonVisibility( )
The confusion seems to stem from a mixing of the business logic and the UI logic. The test isn't whether the button should be shown. Code is going to use the test to decide if the button should be shown. It probably depends on whether some feature should be available. Consider:
if (IsFeatureEnabled()) {
ShowButton();
} else {
HideButton();
}
This is the code where business logic (IsFeatureEnabled()) meets UI (ShowButton()/HideButton()).