I am making a file browser using QTreeView and QFileSystemModel.
It must be selected and scroll the tree to a selected item automatically. But it doesn't work scroll automatically without getting keyboard.
QString strFile = "/usr/bin/qmake";
QFileInfo fi(strFile);
QString dirFile = fi.dir().absolutePath();
QFileSystemModel model;
model.setRootPath("/");
model.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
QTreeView view;
view.setModel(&model);
tree.setCurrentIndex(model.index(strFile));
tree.scrollTo(model.index(strFile));
view.show();
When executing above code, scroll is top but file is selected.
What's the problem not to scroll to selected item?
You can use scrollTo
view.scrollTo(view.currentIndex());
Optional pass the option where you want your item as a second parameter, like: QAbstractItemView::PositionAtTop or other
LE: i noticed that you actually call scrollTo, but you call it for some tree (that we can't see what it is) you should call that for view, same applies for setCurrentIndex.
Related
I want to implement manual controls to a QTreeView object in Qt. (That means there will be programmatical control of everything, including navigation) So far I've implemented navigating / selecting in siblings. However, I want to establish a state where it is easier to control, whether there are expanded folders or not. If there is no such approach implemented in the Qt API, I'm going to have to know if a selected Folder item is expanded or not.
For example, for checking if an item is a folder, I check my directory model and do a string comparison (I know this is not the best way, but I dont know if Qt API features this also):
int MainWindow::checkIfFolder_treeview (void)
{
/* Check if highlighted item is a folder by checking type name*/
QModelIndex index_foldersearch = ui->treeView->currentIndex().sibling(ui->treeView->currentIndex().row(), 2);
QVariant data_foldersearch = ui->treeView->model()->data(index_foldersearch);
//qDebug() << "typeName:" << data_foldersearch.toString();
if (QString::compare("Folder", data_foldersearch.toString()) == 0)
{
/* Selected item is a folder!*/
return 0;
}
else
return -1;
}
To move to the next item, I use:
ui->treeView->setCurrentIndex(ui->treeView->currentIndex().sibling(ui->treeView->currentIndex().row()+1, 0));
ui->treeView->selectionModel()->select(ui->treeView->currentIndex(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
Back to the original questions, any help towards:
determining if a selected item is an expanded or non-expanded folder
easily navigating through items (next item function, and previous item function) without having distinct between sibling, parent, or child functions
is greately appreciated.
Documentation has a function "isExpanded", just pass in the modelindex.
http://doc.qt.io/qt-5/qtreeview.html#isExpanded
For the navigation you can use indexAbove and indexBelow functions. documentation links are given below
http://doc.qt.io/qt-5/qtreeview.html#indexAbove
http://doc.qt.io/qt-5/qtreeview.html#indexBelow
Well, the thing is I have a tabwidget created in qtcreator, with many tabs and in the tabs there are many lineedit and other objects.
The closeable property of the tabWidget is set to true.
I execute the program and close the tabs, but when I want to reopen the tab, it's empty, I'm using this code:
tabs->addTab(new QWidget(),"TAB 1");
I want to use the same tab create on the design of qtcreator.
Your problem is that you are adding empty widget in your code:
tabs->addTab(new QWidget(),"TAB 1");
Instead you need to keep you widgets and add them like that:
QWidget* widget; // it is stored
int index = ui->tabWidget->addTab(widget, "TAB 1");
Where to take these widgets?
It is not enough to set closable to true, you also to use signal/slot:
connect(ui->tabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int)));
And finally:
void YourWindow::closeTab(int index)
{
// do something else
QWidget* widget = ui->tabWidget->widget(index);
ui->tabWidget->removeTab(index);
// here you can remember it and use later when adding tab
}
I have MainWindow form which has Widget inside. And I have another Widget class (promoted to MainWindow) which has only DockWidget inside. In MainWindow I am opening new one and placing into Widget. However when I close DockWidget from close(cross"X") button. Inside my MainWindow it is not cleaning..
Sorry for my bad english better to paste my code here:
qDebug() << ui->widget->layout()->count();
QueryWidget *lQueryWidget = new QueryWidget(this);
ui->widget->layout()->addWidget(lQueryWidget);
So in everytime although I close DockWindow(lQueryWidget), layout()->count() never decrease. I tried to delete everything inside layout like ;
QList<QObject*> child = ui->widget->layout()->children();
foreach (QObject *var, child)
{
delete var;
}
But it never enters foreach loop.. If you check image below you will see that there is something above DockWidget, but it is not visible.. Could you please help me how can I solve this issue ?
To make dockable widget you should use
QDockWidget::setWidget(QWidget * widget)
The widget will be deleted when the dock widget is deleted.
You should not manipulate the dock widget layout.
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.
I want to add a QPushButton inside ListItm, so I have implemented the code as given below. But the button comes in the middle of the list, actually I want it at the lower end of the list item. How is it possible. Also that button click event is not working. Actually I want to disable the item click event directly and by clicking the button inside the QListWidgetItem, I want to enable the item click event. But I am not able to perform this operation. How to do this? I have used the following code snippet:
list=new QListWidget(this);
// list->setStyleSheet("* { background-color:rgb(0,0,0); padding: 10px ; color:rgb(255,255,255)}");
list->setGeometry(0,61,360,475);
list->setSortingEnabled(true);
//connect(list,SIGNAL(itemClicked(QListWidgetItem*)),this,SLOT(ItemClicked(QListWidgetItem*)));
item=new QListWidgetItem();
item->setIcon(QIcon(":/images/Icon.png"));
item->setText("Item1");
item->setSizeHint(QSize(80,80));
item->setBackgroundColor(QColor(200,255,100));
list->addItem(item);
QPushButton *but = new QPushButton(">");
but->setMaximumSize(50,80);
but->setFlat(true);
// but->setGeometry(QRect(500,100,100,100));
but->setStyleSheet("background: transparent; border: none");
QHBoxLayout *layout= new QHBoxLayout();
layout->addWidget(but);
QWidget *widget = new QWidget();
widget->setLayout(layout);
item->setSizeHint(widget->sizeHint());
list->setItemWidget(item, widget);
connect(but, SIGNAL(clicked()), this, SLOT(ItemClicked()));
#if defined(Q_WS_S60)
list->showMaximized();
#else
list->show();
#endif
ItemClicked()
{
int Index = list->currentIndex().row();//Always getting this Index as -1
}
Please have a look on the above code and provide your suggestions.
Thanks...
Reconsider using QPushButton as "click" handle for listwidget. There is a reason why QListWidgetItem is not QObject. QObjects are somewhat "heavy", because of all metadata structures they hold. That's why Qt is not using QObjects in data oriented lists like QListWidgetItem.
About your problem. You will get always -1, until you won't select item by NOT clicking on it's button part, but on item. That's because QPushButton is taking focus away, and doesn't pass click event down to QListWidgetItem. So it may even happend, that you select item with idx = 3, click on button of item with idx = 1 and will get in your slot idx 3.
Actualy, as for me you're performing your whole taks totaly wrong. First of all, I would use QTreeWidget, for multicolumns. Secondly, I would "implement" custom item delegate, to draw "button", and I would set it as delegate for column 1. Then I would catch "click event" normally, but react only for column 1.
| column 0 (actual data exposition) | column 1 (custom delegate, draw button)