Binding NSPopUpButton to NSArray - nsarray

I'm a little lost with bindings on NSPopUpButton. I have a custom class that holds an array of items that I'd like to display in a pop up. These items are subclasses of NSManagedObjects and they are contained in an NSArray. I don't want to use an NSArrayController since I've had lots of trouble changing the selection programmatically and it feels like cluttering the implementation.
The problem is simply that I don't know how to bind the array properly to the pop up. All I have managed to do is list the array items on the pop up menu, but the titles are core data URIs. I believe I could use the description method to change the title, but this does not sound very advisable.
Any ideas how to bind NSArray to the NSPopUpButton properly?

I think I solved it. I simply created these bindings for NSPopUpButton:
"Content" to the items property (of type NSArray*)
"Selected Object" to selectedItem (of type Item*)
Finally "Content Values" to items.name
For the third binding I implemented valueForKeyPath:
- (id)valueForKeyPath:(NSString *)keyPath
{
NSArray *components = [keyPath componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"."]];
if ([components count] == 2 && [components objectAtIndex:0] == #"items")
{
return [self.items valueForKey:[components objectAtIndex:1]];
}
return [super valueForKeyPath:keyPath];
}
The third binding could've been also a separate array for titles, but I this is much more flexible.

Related

Finding a wxMenu's Selected Radio Item

Let's say that I have a group of radio items in a wxMenu. I know that exactly one of these will be checked at any given time.
Does the wxMenu or some other construct hold onto the index of the checked item, or do I need to call the isChecked on each radio item till I find the checked element to find it's index?
I've asked this question about how to do that, but I'd much prefer wxWidgets saved me from doing that everywhere.
No, saving the index of the last selected item (as shown in ravenspoint's answer) or using wxMenuBarBase::IsChecked() until you find the selected radio button is the only way to do it.
For wxWidgets to provide access to the currently selected button it would need not only to store it (which means not forgetting to update not only when the selected changes, but also when items are inserted into/deleted from the menu, so it's already not completely trivial), but to somehow provide access to the radio items group you're interested in, which would require being able to identify it and currently there is no way to do it and adding it isn't going to be particularly simple.
What could be done easily, however, is writing a reusable function int GetIndexOfSelectedRadioItem(int firstItem) that would start at the given item and call IsChecked() on subsequent items until it returns true and return the offset of the item. You should be able to do it in your own code, but if you'd like to include such function in wxWidgets itself (as a static wxMenuBar method, probably), please don't hesitate to send patches/pull requests doing it!
It is easy enough to roll your own.
Bind an event handler to wxEVT_COMMAND_RADIOBUTTON_SELECTED for every button. In the handler, extract the ID of the selected radio button and store it somewhere.
Like this:
ResolMenu = new wxMenu();
ResolMenu->AppendRadioItem(idRcvLoRez,"Low Resolution");
ResolMenu->AppendRadioItem(idRcvMeRez,"Medium Resolution");
ResolMenu->AppendRadioItem(idRcvHiRez,"High Resolution");
ResolMenu->Check( idRcvLoRez, true );
Bind(wxEVT_MENU,&cFrame::onRcvRez,this,idRcvLoRez);
Bind(wxEVT_MENU,&cFrame::onRcvRez,this,idRcvMeRez);
Bind(wxEVT_MENU,&cFrame::onRcvRez,this,idRcvHiRez);
void onRcvRez( wxCommandEvent& event )
{
myRezID = event.GetId();

Replace QWidget with a new QWidget

This questions to me reeks of maybe a lack of understanding of C++, as the possibilities I've considered for my problem all seem to make no sense on why this could be occuring. Feedback appreciated.
I'm using the form designer to create a form class with a table in it. I'm trying to replace the table with another table generated in a helper class. I'm only doing this so I can (hopefully) maintain the nice grid layout I've designed, and through pointer manipulation, get the replacement I desire. Here's some code snippets from the table form constructor and relevant calls :
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
....
setup();
void setup(){
tableData = Utilities::createTable(this->file, tableDelim);
//createTable returns QTableWidget*
... other assignments, and label text updates, which seem to all work
}
My understanding is that tableData is a pointer, and if printed, will give the address of the QTableWidget from the layout. So then if I create a QTableWidget* and then assign tableData to that, tableData should now point to the new widget. Instead, I see only a blank screen.
I tried checking what the tableData pointer is before I assign it to the new QTableWidget*, and after. The second pointer shown is what is generated by createTable() :
QTableWidget(0x101272d40, name = "tableData") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats") QTableWidget(0x10127b3b0, name = "test_sample2.nuc.stats")
It seems the pointer is being reassigned, but the table drawn isn't the right one.
What gives?
My understanding is that you want to design the table layout in designer but fill in the data from an external source.
I would suggest, to just use the QTableWidget that is created in setupUi() and modify Utilities::createTable() such that it becomes Utilities::populateTable(QTableWidget & table, <all the other parameters you need>). (Or use QTableWidget * if you prefer - however I like putting the non-zero assertion responsibility on the caller...)
Apart from that, I agree with Sebastian Lange.
You are right with your assumption. You do set a variable to be a pointer to a object and next you set the variable to be a pointer to another object. You never change any objects, just your variable which is not used to display anything.
You would need to do something like:
//tableData is defined in the header file as a QTableWidget*
tableData = this->findChild<QTableWidget *>("tableData");
parentLayout = tableData->parent()->layout(); //Get the parent widget to add another table.
parentLayout->removeWidget(tableData);
delete tableData;
parentLayout->addWidget(createTable());
You need to use pTheContainerOfTheOriginalTableWidget->addWidget(tableData); See here: http://qt-project.org/forums/viewthread/16547
Be sure you remove the original tableWidget so you don't have two (I assume you don't want two).
If I understand you correctly we have such situation.
call of setupUi (which generated by qt tootls),
there there is something like this(pseudo code):
oldTablePtr = new QTableWidget(parent);
someLayout->addWidget(oldTablePtr);
So parent and layout hold value of oldTablePtr.
And if you set variable oldTablePtr nothing changed.
parent send QPaintEvent to oldTablePtr.
So you need call delete oldTablePtr, that remove this widget from list of childs of parent, and move newTablePtr to the same layout.
There's no need to replace it in code, you can do it in Qt Designer. Just place QTableWidget on form, then rightclick it and choose Promote widget in menu, then you will need just enter your classname.
Currently I don't have Qt Designer near me, so edits will be appreciated.

qt/c++ naming of variables dynamically

I am in the process of developing a html editor in Qt for one of my university assignments, and i am having a problem regarding naming of some variables.
the problem is this:
when the user decides to load their "project" the program iterates through the folder and finds how many .html files are in there, it then creates tabs for them to be displayed in.
I have a custom QTextEdit which has a customer completer and syntax highlighting etc. the problem i am having at the moment is how to create them depending on the number needed.
i create a QStringList of file names:
QStringList m_files;
m_files = aDialog.m_loadDirectory->entryList(QStringList("*.html"),QDir::Files|QDir::NoSymLinks);
then i iterate through each one of the list:
for(int i=0; i<m_files.count();i++)
{
}
and for each one i need to create a new custom QtextEdit
TextEdit *name = new TextEdit;
then add to the tab
tabs->addTab(name,"someTitle");
but as each TextEdit needs to be different for each tab (i think this is correct) i need a different Variable name for each one.
i thought about creating a list/array of TextEdit objects but as i dont know how many i need to use, i could end up easily with too many (wasted memory) or not enough..
any ideas on how i can get around this?
one thought..
would it be possible to create a TextEdit object before the loop
then make a copy of that object in the loop and add the copied object to the tab? (still variable naming problem...)
thanks
but as each TextEdit needs to be different for each tab (I think this is correct)
Yes, you need a different TextEdit in each tab.
I need a different Variable name for each one.
No, you don't need a different variable name for each one. You need different objects, but variable names don't have much to do with that.
A simple:
for (...) {
TextEdit *te = new TextEdit(...);
// set up that text edit in whatever way you need
tabs->addWidget(te, "foo");
}
does exactly what you want. The variable name te is completely irrelevant (it won't even appear in the executable outside of debugging symbols). Each time through the loop, you'll be working on a separate TextEdit instance.
If you need to refer to that TextEdit by name at runtime, you can keep all your widgets in a collection, a QMap for instance.
QMap<QString, QWidget*> all_editors;
...
for (...) {
TextEdit *te = ...;
all_editors[filename] = te;
...
}
You have discarded quickly the only viable solution : put your text edits in a collection. The textedit have to be created with new, so the collection itself will not waste space.
You can use a QPair<QTabWidget*, QTextEdit*> for simplest cases. For more complicated cases create a custom widget, and just make a list of those.
Copying a QObject is a really bad idea. I think the copy constructor is private so you will not even be able to do that

Is there a Dojo list container that sorts child widgets automatically?

I'd like a graphical container that I can add and remove my custom widgets to where I can set a sort function that is automatically applied when these operations take place.
Is there a suitable object in Dojo already that I've missed? Or maybe I'm not thinking about the problem correctly?
If not, are there any examples etc. of a minimal working custom container widget out there?
Dont think there is really - how would a standard component's sort functionality know, with which parameters it should weight the order, when containers can contain any widget type?
Using a layout widget extension would be your best option imho. They each have a function to add children, following this prototype:
addChild(/*Object*/ dijit, /*Integer?*/ insertIndex)
The dijit.layout.StackContainer is a good starting point, it inherits from dijit._Container (and dijit.layout._LayoutWidget). So you choose when to call the extension functionality of your override.
dojo.declare("my.Container", [dijit._Container], {
getSortOrder : function(newDijit) {
var newIndex = -1; ??
// something to work with
var currentChildren = this.getChildren();
var currentDescendants = this.getDescendants();
return newIndex;
},
addChild: function(dijit, index) {
// figure out index
arguments[1] = this.getSortOrder(dijit);
this.inherited(arguments);
}
});
But be aware, that layoutwidgets has more to it then choosing order, also positioning like with bordercontainer's region parameter.
Use SitePen's dgrid, then define a List widget with a column of type Editor. Send your custom widget to the Editor's parameter. dgrid's List widget should be able to sort as if it were a grid based on your data, and the Editor column should be able to display anything you want as part of a List's item's content.
If you need anything I'll be around. Luck,

Using the GroupBoxes in Qt

I'm a student programmer and I am using Qt to build a GUI application. I'm trying to ensure that some check boxes are checked in order to proceed. These check boxes enable or disable the group box itself and are part of the QGroupBox class. Accepted combinations could be either or both. The problem I am running into is getting the boolean value(at least that's what I think it is) from the QGroupBox member function QGroupBox::setChecked(bool) and use it to determine whether or not to display an error message. I have tried several methods and reference Qts documentation hoping for a good example. Because the QGroupBox I'm trying to use is a member of my ui class I tried creating a new instance of QGroupBox and setting it to the values of the ui. Then; using an if statement, find out whether or not the boxes are check or not. Here's my code for this:
QGroupBox activeParticleInjection = ui->groupBoxParticleInjection;
QGroupBox activeFluidInjection = ui->groupBoxFluidInjection;
if (activeParticleInjection::setChecked(false) && activeFluidInjection(false));
{
QMessageBox noInjectionSelectedError;
noInjectionSelectedError.setText("Error: No injection type selected");
noInjectionSelectedError.exec();
}
else
{
transData.particleInjectionActive = activeParticleInjection::setChecked();
transData.fluidInjectionActive = activeFluidInjection::setChecked();
This doesn't work; starting with the way I'm trying to pass the Ui properties to the new instance of QGroupBox. I know that is question is relatively generic question but I tried passing the ui checkbox directly and that caused even more issues. I looked through the documentation and that led me to the way im trying to do it know; with no luck. I was hoping for some feedback on a better method of handling QGroupBox. Being a student sometimes its hard to see the answer especially when dealing with such unique members as the ones put together in QT.
Prior to changes I was using this method to build this process; and I received errors for the way my if parameters were setup. Compile error was : no matching function for call to 'QGroupBox::isChecked(bool)'
if (ui->groupBoxFluidInjection->isChecked(false) && ui->groupBoxParticleInjection->isChecked(false));
{
QMessageBox noInjectionSelectedError;
noInjectionSelectedError.setText("Error: No injection type selected");
noInjectionSelectedError.exec();
}
else
{
transData.particleInjectionActive = ui->groupBoxParticleInjection->isChecked();
transData.fluidInjectionActive = ui->groupBoxFluidInjection->isChecked();
}
I have been using these sites for most help:
QGroupBox
QCheckBox
You're mixing several things:
The QGroupBox instances in ui are pointers, so you must assign them to a QGroupBox* (pointer), not a QGroupBox (object on the stack).
:: is used with methods only if the method you call is static (class method), which is not the case here.
setChecked() is a setter setting the checked state of the group box. It doesn't return anything (void), so you cannot use them as conditions. What you want there is the getter bool QGroupBox::isChecked().
Your code snippet cleansed:
QGroupBox* activeParticleInjection = ui->groupBoxParticleInjection;
QGroupBox* activeFluidInjection = ui->groupBoxFluidInjection;
if (!activeParticleInjection->isChecked() && !activeFluidInjection->isChecked())
{
QMessageBox::critical(this, tr("Error"), tr("No injection type selected"));
}
else
{
transData.particleInjectionActive = activeParticleInjection->isChecked();
transData.fluidInjectionActive = activeFluidInjection->isChecked();
}
Not really sure what you tried to do in your code, but that's actually a lot easier to achieve. Also don't try to create copies (which you do in your example). Work with references or pointers in that case!
QGroupBox group("my group box"); // of course this might be a class member, too
group.setCheckable(true);
// do other things...
if(group.isChecked())
{
// do whatever if it's checked
}
else
{
// do stuff if it isn't checked
}
To check for at least one of multiple groups (or check boxes) being checked:
if(group1.isChecked() || group2.isChecked())