Get data from selected row of gtk treeview - gtkmm, c++ - c++

I have a GTK application that has a window with a treeview and a button. When the button is clicked I need to get the data from the first (and only) column of the selected row in the treeview.
This is the class for the columns:
class ModelColumns:
public Gtk::TreeModel::ColumnRecord{
public:
ModelColumns(){ add(m_port_name); }
Gtk::TreeModelColumn<Glib::ustring> m_port_name;
};
This is like in the example here but with only one column: http://www.lugod.org/presentations/gtkmm/treeview.html
This is the button click signal handler at the moment:
tvPorts is the treeview widget
tvPortsList is the listStore for the treeview
static
void on_btnPortSelectOK_clicked (){
Glib::RefPtr<Gtk::TreeSelection> selection = tvPorts->get_selection();
Gtk::TreeModel::iterator selectedRow = selection->get_selected();
//Now what?
//Need to get data from selected row to display it.
}
I have searched the documentation and many examples to try and find out what to do next but can't find any examples for gtkmm, I can only find examples for c or python implementations.
As far as I can tell, I need to get a TreeRow object from my iterator (selectedRow) how do I do this?
Thanks.
Update:
I am now using this code and it almost works.
The only problem is that it prints the previous selection.
The first time I select something and then press the button it prints only a new line. The second time it prints what was selected the first time, the third prints the second, etc.
Glib::RefPtr<Gtk::TreeSelection> selection = tvPorts->get_selection();
Gtk::TreeModel::iterator selectedRow = selection->get_selected();
Gtk::TreeModel::Row row = *selectedRow;
Glib::ustring port = row.get_value(m_Columns.m_port_name);
printf("\nselected port: %s", port.data());
This seems odd.
(m_Columns is an instance of the ModelColumns class)
Update 2:
Fixed the problem by adding fflush(stdout);
It all works now, thanks.

The docs say to simply dereference the iter to get the TreeRow:
Gtk::TreeModel::Row row = *iter; // 'iter' being your 'selectedRow'
std::cout<<row[0];

Related

Qt trying to enable scrolling slightly beyond last element in QTableView

I'm making a sort of an Excel-type application in which I can load a tab-delimited text file and I am able to edit cells... etc
It's useable but I have an issue related to me allowing the user to "freeze" a number of columns/rows. ("Frozen" rows/columns can only be one of the first ones and are then "frozen", i.e. always displayed even when scrolling)
The whole frozen Col/Row is working but I would like the user to be able to scroll slightly past the last Col/Row in order to be able to only ever display full cells.
Right now when reaching the end of the scrollbar I end up with a partial leftmost column and topmost row because it's only displaying up to the last full col/row and not going a wee bit further for all content to be displayed fully.
I've tried doing adding some space to the maximum scrollbar value once everything is loaded in the table but it seems to have no effect :
table->horizontalScrollBar()->setMaximum(table->horizontalScrollBar()->maximum() + t->horizontalScrollBar()->singleStep()*2);
I tried multiple values too.
(Edit) There may be some Qt code that "snaps" the QTableView viewport back to the edge of the last cell automatically...
(Edit2) I connected verticalScrollbar's rangeChanged() signal to a custom slot with the following code:
void MyTableView::onRangeChanged(int min, int max) {
QScrollBar *sender = verticalScrollBar();
int newVMax = max + 20;
sender->blockSignals(true);
sender->setRange(min, newVMax);
sender->blockSignals(false);
}
Sadly there is definitely a snapback mechanic when scrolling to the end of verticalScrollbar...
Gif of snap back issue
(Edit3) The snap back may be related to:
void QHeaderViewPrivate::setScrollOffset(const QScrollBar *scrollBar, QAbstractItemView::ScrollMode scrollMode)
{
Q_Q(QHeaderView);
if (scrollMode == QAbstractItemView::ScrollPerItem) {
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
q->setOffsetToLastSection();
else
q->setOffsetToSectionPosition(scrollBar->value());
} else {
q->setOffset(scrollBar->value());
}
}
mainly:
if (scrollBar->maximum() > 0 && scrollBar->value() == scrollBar->maximum())
q->setOffsetToLastSection();

using one Qcombobox to set value to several labels, C++

im trying to set the value from a combobox to multiple Qlabels, the idea is to populate the QcomboBox with all the values, then according to the number, (ejem 15.6) the corresponding label should change the problem is, theres too many of them to simply use a switch of something similar, but all the names of the labels are similar, HumSec_val156 corresponds to 15.6 the main idea was to use
Silo* silo = new Silo;
QString number = widget.QComboBox->currentText();
QString nameOfLabel = "HumSec_val";
nameOfLabel.append(QString::number(number));
silo->findchild<QLabel*>(nameOfLabel)->setText(valuefromCombobox);
but everytime it simply return an empty string, i did try using somthing simplier like
widget.nameOfLabel->setText(valuefromComboBox);
but nameOfLabel its just a qstring so i can mix it with the code generated from designer. Any idea what can i do? do i need to create something like a scoped enum or similar?
below i add a picture of what im doing
If I would do something like this, I would probably create a QHash<QString, QLabel*> and use that as a cache to find the matching QLabel for each name.
Declaration:
QHash<QString, QLabel*> m_hash
Storing value:
m_hash[labelName] = labelPtr;
Reading value:
QLabel* labelPtr = m_hash.value(labelName, nullptr);
if (labelPtr)
{
// Access label
}
When you remove a label remember to remove it from the hash as well:
const QString key = m_hash.key(labelPtr);
m_hash.remove(key);

Getting a string from QGraphicsSimpleTextItem from QGraphicsItem foreach loop?

I am making an image annotation system Using qrect and Simple text items.
I am trying to store the string values from the QGraphicssimpletext items into a JSON file to save and load the annotation boxes. The rectangles work fine but I cannot understand how to get a string value. This is the foreach I am trying to loop through for each item, and as the text items are children of the rectangles the position does not matter.
foreach(QGraphicsItem* item, items())
{
arrayPosX.push_back(item->x());
arrayHeight.push_back(item->boundingRect().height());
arrayWidth.push_back(item->boundingRect().width());
arrayPosY.push_back(item->y());
arrayAnnotation.push_back(item->?);
}
Both the simple text and rect items are added to the scene using
itemToDraw = new QGraphicsRectItem;
this->addItem(itemToDraw);
simpleTextToDraw = new QGraphicsSimpleTextItem;
this->addItem(simpleTextToDraw);
I would simply like to know how I could get the string values from the simple text item as to allow saving and loading of both strings and boxes, not just boxes which the current system can do.
You have to cast and verify that the pointer is not null:
// ...
arrayPosY.push_back(item->y());
if(QGraphicsSimpleTextItem* text_item = qgraphicsitem_cast<QGraphicsSimpleTextItem *>(item)){
arrayAnnotation.push_back(text_item->text());
}

Why is QLineEdit::setCursorPosition(int) selecting(highlighting) text?

I have an editable QComboBox that allows a user to type in a name for a new object and add it to the list. They can also edit names for existing items in the list. The problem is...say I have an item in the list called "AF" and I want to rename it to "ABCDEF". My first problem was if I placed the cursor in between 'A' and 'F' and started typing the cursor would jump to the end after typing 1 letter. So I would get "ABFCDE" unless I manually moved the cursor after each letter typed.
I fixed this by using
// slot connected to textEditChanged(QString) signal from QComboBox
void textChanged(const QString &text)
{
int pos = QComboBox->lineEdit()->custorPosition();
stuff...
QComboBox->setItemText(idx, text);
QComboBox->lineEdit()->setCursorPosition(pos);
}
and that works but unfortunately this caused a new problem.
setCursorPosition will subsequently select (highlight) all text beyond the new cursor location. So in the "AF" to "ABCDEF" example... I place the cursor between 'A' and 'F', type B and the cursor stays after "AB" and before 'F' but 'F' is highlighted. The next key press will replace the 'F' entirely. It will highlight more than 1 character, it highlights every character to the right of the cursor after it is moved.
I tried this to no avail.
QComboBox->lineEdit()->deselect();
I also tried this just as a test and it incorrectly exhibited the same behavior.
QComboBox->lineEdit()->moveCursorBackward(false,2);
The false parameter is supposed to not select the text the cursor moves past but it does anyway.
Anyone have any ideas on what's causing this?
I also encountered this problem. Here's what solved it for me for anyone interested:
First connect the signal but make sure it is queued!
connect(_comboBox, SIGNAL(editTextChanged(const QString&)), this, SLOT(slotTextChanged(const QString&)), Qt::QueuedConnection);
and for the slot:
void ViewListWidget::slotViewNameChanged(const QString& /*name*/) {
int index = _viewComboBox->currentIndex();
int cursorPosition = _viewComboBox->lineEdit()->cursorPosition();
// Since we are using a queued connection, get the current QLineEdit text
// instead of relying on the signal argument, which might be out of sync
QString name = _viewComboBox->lineEdit()->text();
_viewComboBox->blockSignals(true);
_viewComboBox->setItemText(index, name);
_viewComboBox->blockSignals(false);
_viewComboBox->lineEdit()->setCursorPosition(cursorPosition);
}
You should also probably disable auto-complete:
_comboBox->setCompleter(0);

Quiz Game / Clicking a button to add text to label

Im making a quiz. And it works like this, When you are answearing a question, you have to click some buttons with text on them to answear.
Example () = button
(G) (L) (O) (R) (I) (O) (U) (S)
And they have to spell glorious in that label correctly. And when they click the answear button, if the label says Glorious, they go to the next level. And if it says something else like Gloirous a message saying wrong answear will come up.
The problem :
The problem is that when i click a button, it adds text to the label.
But when i click another button the previous text dissapears and the new comes in.
I hope you guys understand what i want here! My english is not the best but if you want me to post some code i can do that !;)
You need to save previous text, and append new text to previous.
label.setText(label.text() + newText)
Try this:
[yourLabel setText:[yourLabel.text stringByAppendingString:#"%#", yourButton.text]];
Don't save the text to a label. Display the text in a label, but store it somewhere else.
Create an instance variable "answerString". Append each letter to the answer string, and then display the answer string to your label:
NSString *answerString;
Also, don't write a different IBAction method for each button. Put numeric tags on each button, attach them to the same method, and use the tag number to figure out which button was pressed. Something like this:
typedef NS_ENUM(NSInteger, buttonTags)
{
aButton = 100,
bButton = 101,
cButton = 102
//and so on for the entire alphabet, or for the letters you need
}
- (IBAction) buttonAction: (UIButton *) sender;
{
int button_id = sender.tag;
switch (button_id)
{
case aButton:
answerString = [answerString stringByAppendingString: #"a"];
break;
case bButton:
answerString = [answerString stringByAppendingString: #"b"];
break;
}
answerLabel.text = answerString
}
If you have buttons for all 26 letters it probably makes more sense to do some math on the tag numbers to get the unicode value of each character rather than having a switch statement with 26 cases, but you get the idea.