How to take my widget in QListWidget, using currentItemChanged signal? - qt

I have QListWidget pointer (pListWidget). A have my custom (QCustomItem) widget, inerited from QWidget and containing some data. I adding some widgets into the list:
int iMyData = 555;
...
QListWidgetItem *pListWidgetItem = new QListWidgetItem();
QCustomItem *pCustomWidget = new QCustomItem(iMyData);
pListWidget->addItem(pListWidgetItem);
pListWidget->setItemWidget(pListWidgetItem, pCustomWidget);
...
This part of code may be in cycle (adding few widgets).
Also I detecting item changing by connection:
connect(pListWidget, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), this, SLOT(slotItemChanged(QListWidgetItem*,QListWidgetItem*)) );
And slot realization:
void QSomeForm::slotItemChanged(QListWidgetItem* pCurrent, QListWidgetItem* pPrevious)
{
QCustomItem *pCustomWidget = // And this is my question: how to take my custom widget in this block code using pListWidget and pCurrent?
// Processing pCustomWidget
int iMyData = pCustomWidget->iMyData(); // In current example I want to see 555 here
}
How I can extract my widget from QListWidget ? Thanks! I hope on your help!

Read the doc. If you have found QListWidget::setItemWidget() you can find:
QWidget * QListWidget::itemWidget(QListWidgetItem * item) const

Related

Subclassing QUiloader and reimplementing createWidget function of it

I needed to read widget classnames, names etc from gui loaded via QUiloader.
And I got answer here that I needed to subclass QUiloader and reimplement its method.
I have MainWindow, and via menu/toolbar I load the file, and show it. And when I load I want to know what elements are in that gui to work further with them.
The code I got from a user here:
class UiLoader : public QUiLoader
{
Q_OBJECT
public:
QStringList *wlist;
UiLoader(QObject *parent = 0) : QUiLoader(parent) {}
virtual QWidget* createWidget(const QString &className, QWidget *parent =0, const QString &name = QString())
{
QWidget* widget = QUiLoader::createWidget(className, parent, name);
//here do my stuff with className, parent, name
return widget;
}
};
I used Uiloader to load my file. And it is working.
My question now is how I intercept createWidget before returning widget, I want to get the list of widget and then return Widgets.
I do not know how what is the efficient way to create a list as simple as this one:
0=>TextBox, 1=>Button, ...
I really do not care about the structure I just need to know which one comes first and what it is.
Thanks.
I wouldn't reimplement class loader at all honestly.. May be only if you need to 'inject' something into existing code which use QUiLoader a lot.. but in general only thing you need:
pWidget = ...->createWidget(...);
QList<QWidget *> widgets = pWidget->findChildren<QWidget *>();
here you go, your widgets contains list of all form components..

QT: changing the tab traversal order on runtime?

you might be able to tell that I'm pretty new to QT...
My program contains a window with several Widgets in a QGridLayout. Some of these Widgets have a layout and child widgets themselves. Pressing the Tab key moves the focus like I expect it to, in the order I created the widgets.
Problems occur when a widget changes it's content (I do that by deleting all child widgets and then constructing new ones.) If I do that, new widgets are moved to the end of the tab chain (that indicates to me, that tab order is kind of global for a window). I have tried to use QWidget::setTabOrder() to reorder all widgets (I tried both, setting tab order for only the contends of the main window and setting it for the children too) but the actual order doesn't change. I did this by emitting a signal when the contend of a widget changes and connecting that to a slot on my main Window.
I think I understand the way the setTabOrder() function should work. I do something similar to this:
QWidget* a = firstWidget;
QWidget* b = secondWidget;
QWidget::setTabOrder(a,b);
for (int i = 0; i < widgets.size(); ++i) {
a = b;
b = widgets[i];
QWidget::setTabOrder(a,b);
}
Is there anything special one has to do when changing the tab order?
I also tried to reimplement focusNextPrevChild(bool next) and focusInEvent(QFocusEvent* e) similar to what can be found at this site. 1
I managed to mess up tab order a lot more like this... is this approach a step in the right direction?
I'm sorry if this is something simple that I managed to miss, but I'm struggling for a while now and I can't find a solution.
Any help is very appreciated.
I had the same problem, and resolved it using the info Tim Meyer provided in the comments.
Tab order is not hierarchical - calling setTabOrder on a parent widget that doesn't accept focus will not cause the focus to be passed to the child. You will need to fetch the appropriate children from the widget and set the order on them
In my case, a dynamically constructed QTreeWidget contained editable widgets, and I needed to reset setTabOrder to account for widgets being created out-of-order.
The following code is (most) of the implementation
// Perform a depth-first gather of the child widgets of this item
void gatherTabWidgets( QObject* item, QWidgetList& tabWidgets )
{
if (item->isWidgetType())
{
QWidget* itemWidget = static_cast<QWidget*>(item);
if (itemWidget->focusPolicy() & Qt::TabFocus)
tabWidgets.push_back( itemWidget );
}
const QObjectList& children = item->children();
for (QObjectList::const_iterator itr = children.begin(); itr != children.end(); itr++)
{
gatherTabWidgets( const_cast<QObject*>(*itr), tabWidgets );
}
}
// Perform a depth-first gather of the child items widgets;
void gatherTabWidgets( QTreeWidgetItem* item, QWidgetList& tabWidgets )
{
QWidget* itemWidget = fetchWidgetForItem( item );
gatherTabWidgets( itemWidget, tabWidgets );
for (int i = 0; i < item->childCount(); i++)
{
gatherTabWidgets( item->child( i ), tabWidgets );
}
}
void VETreeWidget::sortTree()
{
// Ensure ordering is maintained.
sortItems( 0, Qt::AscendingOrder );
// Once the items have been re-ordered, re-create the tab ordering
QTreeWidgetItem* baseItem = topLevelItem( 0 );
QWidgetList tabWidgets;
gatherTabWidgets( baseItem, tabWidgets );
if (!tabWidgets.empty())
{
QWidget* lastWidget = tabWidgets.first();
// Connect this treeview to the first widget. This ensures
// if the treeview is tabbed-to, it will tab to the correct sub-widget
setTabOrder( this, lastWidget );
for (QWidgetList::iterator itr = tabWidgets.begin() + 1; itr != tabWidgets.end(); itr++)
{
setTabOrder( lastWidget, *itr );
lastWidget = *itr;
}
}
}

How to make this effect in qt: adding a new lineedit when I click a button

Newbie here. I want to have a GUI effect in my dock widget that whenever I click "add more" button or link, a new lineEdit field appears in the bottom.
I saw many software has something like
point-1 (_____,_____)
point-2 (_____,_____)
+ Add More Points
And when you click "+ Add More Points", a new point-3 will show up and wait for the input.
The code I have now is something like this:
#include "perfectPanel.hpp"
perfectPanel::perfectPanel(QWidget *parent) : QWidget(parent)
{
setupUi(this);
readInfo();
connect
(
btn_accept,
SIGNAL(clicked()),
this,
SLOT(readInfo()),
Qt::UniqueConnection
);
}
// Destructor
perfectPanel::~perfectPanel()
{}
void perfectPanel::readInfo()
{
xObject_ = vtkDoubleArray::New();
yObject_ = vtkDoubleArray::New();
xObject_->InsertNextValue( lineEdit_xObject01X->text().toDouble() );
xObject_->InsertNextValue( lineEdit_xObject02X->text().toDouble() );
yObject_->InsertNextValue( lineEdit_yObject01Y->text().toDouble() );
yObject_->InsertNextValue( lineEdit_yObject02Y->text().toDouble() );
}
You'll need to add that + Add More Points button to the perfectPanel class. Let's say you've already done that with this declaration in your class' private data section:
QPushButton* m_AddPoint;
Now, connect the button's clicked() signal to some slot to add the point. From the example code, you seem to already know how to do this, so I won't go into the specifics. Let's say you've connected the button's click event to the addPoint function.
void perfectPanel::addPoint()
{
/* The "this" argument is needed to prevent memory leaks */
QLineEdit* Field = new QLineEdit(this);
/* Your perfectPanel class has some layout where the existing LineEdit rows
are. I'm assuming m_Layout is a pointer to that layout here. */
m_Layout->addWidget(Field);
Field->show();
}

Simple way to get all visible items in the QListView

I am trying to develop an image gallery application using Qt Framework. The application loads all the images from the selected folder and those images are displayed using QListView control.
But now i want to reduce the memory consumption by loading only the images that are visible to user. Since there is no direct function to get all the visible items in the view, i am not able to achieve this.
You can get the visible items of a list view using the indexAt function. For more details and an example you can check the following article:
http://qt-project.org/faq/answer/how_can_i_get_hold_of_all_of_the_visible_items_in_my_qlistview
I found it! You have to connect the vertical scrollbar of the listwidget to a signal:
connect(ui->listWidget->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(launch_timer()));
Every time the user scrolls, the valuechanged(int) signal is being omitted! The thing is that you shouldn't run the code provided by webclectic in this question every time the value of the vertical scrollbar of the listwidget changes, because the program will be unresponsive with so much code to run in so little time.
So, you have to have a singleshot timer and point it to the function that webclectic posted above. When launch_timer() is called, you do something like this:
if(timer->isActive()){
timer->stop();
timer->start(300);
}
else
timer->start(300);
and the timeout() signal of timer will be connected to the slot webclectic talked about. This way, if the user scrolls quickly all the way down only the last items will be updated. Generally, it will be updated anything visible for more than 300 milliseconds!
I think what you need is to implement your own model (take a look to the QAbstractListModel documentation) so that way you could decide when you have to load more images to show and maybe free some of the images that became non-visible.
although this is not so simple in Qt 4 but
it is always simple to copy below:
#include <private/qlistview_p.h>
class QListViewHelper : public QListView
{
typedef QListView super;
inline QListViewHelper() {} //not intended to be constructed
public:
inline static QVector<QModelIndex> indexFromRect(const QListView *view,
const QRect &rect)
{
const QListViewPrivate *d = static_cast<const QListViewPrivate *>(QObjectPrivate::get(view)); //to access "QListViewPrivate::intersectingSet(...)"
const QListViewHelper *helper = static_cast<const QListViewHelper *>(view); //to access "QListView::horizontalOffset()"
return d->intersectingSet(rect.translated(helper->horizontalOffset(), helper->verticalOffset()), false);
}
inline static QVector<QModelIndex> visibleItems(const QListView *view)
{ return indexFromRect(view, view->rect()); }
inline static QModelIndex firstVisible(const QListView *view)
{ return visibleItems(view).value(0); }
inline static QModelIndex lastVisible(const QListView *view) {
const QVector<QModelIndex> &items = visibleItems(view);
return items.value(items.count() - 1);
}
};
void ourTest(const QListView *view) {
QModelIndex &index = QListViewHelper::firstVisible(view);
qDebug("QListViewHelper: first visible row is %d", index.row());
index = QListViewHelper::lastVisible(view);
qDebug("QListViewHelper: last visible row is %d", index.row());
}
usage:
QModelIndex &index =
QListViewHelper::firstVisible(listViewPointerHere)
note: since it does use Qt 4.8 private-headers it may no longer work in latter versions and will need some changes.
You can keep track of all the elements that are drawn per paint event. I used a delegate and overloaded the paint event.
I also overloaded the paint event in the view. During this call, all the visible delegates will get a paint event.
If you just need to know if an item is visible, you can increment a frame count in view->paintEvent and set that number in the delegate item. The item is visible of the item matches the current frame number.
If you need a list of all visible items, clear the visible item list in view->paintEvent and add each item in the int the delegate->paintEvent to the visible items list.

How to insert QPushButton into TableView?

I am implementing QAbstractTableModel and I would like to insert a QPushButton in the last column of each row. When users click on this button, a new window is shown with more information about this row.
Do you have any idea how to insert the button? I know about delegating system but all examples are only about "how to edit color with the combo box"...
You can use
QPushButton* viewButton = new QPushButton("View");
tableView->setIndexWidget(model->index(counter,2), viewButton);
The model-view architecture isn't made to insert widgets into different cells, but you can draw the push button within the cell.
The differences are:
It will only be a drawing of a pushbutton
Without extra work (perhaps quite a bit of extra work) the button won't be highlighted on mouseover
In consequence of #1 above, you can't use signals and slots
That said, here's how to do it:
Subclass QAbstractItemDelegate (or QStyledItemDelegate) and implement the paint() method. To draw the pushbutton control (or any other control for that matter) you'll need to use a style or the QStylePainter::drawControl() method:
class PushButtonDelegate : public QAbstractItemDelegate
{
// TODO: handle public, private, etc.
QAbstractItemView *view;
public PushButtonDelegate(QAbstractItemView* view)
{
this->view = view;
}
void PushButtonDelegate::paint(
QPainter* painter,
const QStyleOptionViewItem & option,
const QModelIndex & index
) const
{
// assuming this delegate is only registered for the correct column/row
QStylePainter stylePainter(view);
// OR: stylePainter(painter->device)
stylePainter->drawControl(QStyle::CE_PushButton, option);
// OR: view->style()->drawControl(QStyle::CE_PushButton, option, painter, view);
// OR: QApplication::style()->drawControl(/* params as above */);
}
}
Since the delegate keeps you within the model-view realm, use the views signals about selection and edits to popup your information window.
You can use setCellWidget(row,column,QWidget*) to set a widget in a specific cell.

Resources