Qt QScrollArea autoscroll - c++

I'm having problems with QLabel and QScrollArea. I'm trying to make QScrollArea to scroll automatically, but can't find any information about it..
Firstly, I'm using QLabel inside QScrollArea, then QLineEdit outside from QScrollArea. When I type text in QLineEdit, it writes to QLabel and the new line. Whenever it reaches to end of area, QScrollArea doesn't scroll automatically.. How can I do that?
Thank you.

Can't you use QLineEdit itself instead of Qlabel(if u are using only text)?, so that you dont have to use QScrollArea also.
[edit]
What if you set the verticalSlider position to Label->height()
void MainWindow::on_lineEdit_returnPressed()
{
ui->label->setText(ui->label->text() + ui->lineEdit->text() + "\n");
ui->ScrollArea->verticalScrollBar()->setSliderPosition(label->height())
}

Take a look at this example: http://qt-project.org/forums/viewthread/23790/
Without to see your code that is difficult to be more precise ...
[EDITED] Try this:
void MainWindow::on_lineEdit_returnPressed()
{
ui->label->setText(ui->label->text() + ui->lineEdit->text() + "\n");
ui->lineEdit->moveCursor (QTextCursor::Start) ;
ui->lineEdit->ensureCursorVisible() ;
...
}

Related

Strange behavior with QTreeView / QFileSystemModel / QLineEdit

I have a QTreeView linked to a QFileSystemModel. I also have a QLineEdit with two purposes :
when the user click the QTreeView, the QLineEdit is populate with the item clicked (path & filename if applied)
when the user edit the QLineEdit and press enter, I want to :
a. synchronize the QTreeView to that position if the path exist
b. if the path do not exist, I want to repopulate the QLineEdit with the current position of the QTreeView
Everything is working well except when the condition 2a above is met, I want to :
return focus on QTreeView
expand the current folder
resize the 1st column to contents
and scroll the view to that index (scroll to top)
Here is the code I put in place :
QDirectorySelector::QDirectorySelector(QString const & title, QWidget *parent)
: QWidget(parent)
{
mDirectoryModel = new QFileSystemModel;
mDirectoryModel->setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
mDirectoryModel->setRootPath("");
mDirectoryTitle = new QLabel(title);
mDirectoryView = new QTreeView;
mDirectoryView->setModel(mDirectoryModel);
mDirectoryView->setSortingEnabled(true);
mDirectoryView->sortByColumn(0, Qt::AscendingOrder);
mDirectoryView->setSelectionMode(QAbstractItemView::ExtendedSelection);
mDirectoryEdit = new QLineEdit;
QVBoxLayout * layout = new QVBoxLayout;
layout->addWidget(mDirectoryTitle);
layout->addWidget(mDirectoryView);
layout->addWidget(mDirectoryEdit);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
connect(mDirectoryView, &QTreeView::clicked, this, &QDirectorySelector::synchronizeEditFromTree);
connect(mDirectoryEdit, &QLineEdit::returnPressed, this, &QDirectorySelector::synchronizeTreeFromEdit);
connect(this, &QDirectorySelector::synchronizationDone, this, &QDirectorySelector::reactToExpansionStep1, Qt::QueuedConnection);
connect(this, &QDirectorySelector::synchronizationStep1Done, this, &QDirectorySelector::reactToExpansionStep2, Qt::QueuedConnection);
}
void QDirectorySelector::synchronizeEditFromTree(QModelIndex const & index)
{
QString directory{ mDirectoryModel->fileInfo(index).absoluteFilePath() };
mDirectoryEdit->setText(directory);
}
void QDirectorySelector::synchronizeTreeFromEdit()
{
if (QDir(mDirectoryEdit->text()).exists()) {
mDirectoryView->setFocus();
mDirectoryView->setCurrentIndex(mDirectoryModel->index(mDirectoryEdit->text()));
mDirectoryView->setExpanded(mDirectoryView->currentIndex(), true);
emit synchronizationDone(mDirectoryView->currentIndex());
} else {
selectDirectory(mDirectoryView->currentIndex());
}
}
void QDirectorySelector::reactToExpansionStep1(QModelIndex const & index)
{
mDirectoryView->resizeColumnToContents(0);
emit synchronizationStep1Done(mDirectoryView->currentIndex());
}
void QDirectorySelector::reactToExpansionStep2(QModelIndex const & index)
{
mDirectoryView->scrollTo(mDirectoryView->currentIndex(), QAbstractItemView::PositionAtTop);
}
If I type an existing path and press enter I got this unexpected behavior :
the focus is done (ok)
the current index of the view is done correctly (ok)
the expension of the sub folder is done (ok)
the resize of the 1st column is done only at the path level without including the expended part (not expected)
the scroll to is not done at all (not ok)
At this point, if I return to the QLineEdit and press enter again, everything is done correctly. In fact, I observed this pattern, if the specified folder was never "open" (seen/loaded/expended), I get the unexpected behavior. If the specified was "open" (seen/loaded/expended), I get the expected behavior.
I also try to call two times the code in the finishDirectoryEditing without any success. Everything is the same.
Is anyone have any Idea of what is happening here? And better, any suggestion to solve this unexpected behavior.
I think that the QTreeView working with the QFileSystemModel is already too awkward in term of behavior. I mean, it never hide the expansion mark of an empty folder. May be it's possible to change this but I got no success either with the fetch more strategy I found elsewhere on the net.
Thanks to all!

Accessing a the click() slot of a button generated during runtime - Qt Creator

I have a GUI project in Qt Creator that functions as a shopping list. I am using a QLineEdit to add items to a QTableWidget. The user types something in, presses the QPushButton. The slot then adds a new row to the QTableWidget with the input, in the first column, and a new QPushButton in the second column. I then want the user to be able to press the button and have it clear that row, but I don't know how to access that slot, or sender (I'm not sure the proper term.) Here is the code so far. itemList is my QTableWidget, itemInput is the QLineEdit.
void MainWindow::on_btnAddItem_clicked()
{
ui->itemList->insertRow(ui->itemList->rowCount());
ui->itemList->setItem((ui->itemList->rowCount())-1,0,new QTableWidgetItem(ui->itemInput->text()));
QPushButton *clear = new QPushButton("Clear",this);
ui->itemList->setIndexWidget(ui->itemList->model()->index(ui->itemList->rowCount()-1, 1), clear);
ui->itemInput->clear();
}
Here is when the program is initially run. Once they click the button, it runs on_btnAddItem_clicked()
Then it looks like this, and I want to make the clear button remove the row it is a part of.
Do I need to create a new slot? Any help?
You will need to make your own button class and inherit QPushButton. Something like this :
class MyButton : public QPushButton {
public:
MyButton();
QTableWidgetItem *titem;
}
And here you MainWindow :
void MainWindow::on_btnAddItem_clicked()
{
ui->itemList->insertRow(ui->itemList->rowCount());
ui->itemList->setItem((ui->itemList->rowCount())-1,0,new QTableWidgetItem(ui->itemInput->text()));
MyButton *clear = new MyButton("Clear",this);
clear->titem = ui->itemList->item(ui->itemList->rowCount()-1, 0);
connect(clear, SIGNAL(clicked()), SLOT(on_btnClear_Clicked()));
ui->itemList->setIndexWidget(ui->itemList->model()->index(ui->itemList->rowCount()-1, 1), clear);
ui->itemInput->clear();
}
void MainWindow::on_btnClear_Clicked()
{
MyButton *btn = (MyButton*)QObject::sender();
ui->itemList->removeRow(btn->titem->row());
}
Please note, it is only step to do it.

The inferior stopped because it received signal from the Operating System error on resizable scrollarea

I have a QScrollArea inside QTabWidget and I have a QWidget beside my QTabWidget. I want QScrollArea to be resized when my main window is resized, so I have made this code like this:
void frmSummaryContact::on_btnAddNewContact_clicked()
{
MainWindow *mnWindow = qobject_cast<MainWindow *>(this->parent()->parent()->parent()->parent()->parent()->parent());
QTabWidget *tbWidget = qobject_cast<QTabWidget *>(this->parent()->parent()->parent()->parent());
frmDetailContact *frm = new frmDetailContact(mnWindow, "input", -1, mnWindow->rightPane());
QScrollArea *scrlForm = new QScrollArea;
scrlForm->setWidgetResizable(true);
scrlForm->setWidget(frm);
mnWindow->AddNewTab(tbWidget, scrlForm, "Add Contact");
}
my QTabWidget is in different form, so I cast it with qobject_cast. Meanwhile in another form, I have a toogle button to hide QWidget so my QTabWidget get wider. So in that form I have a code like this:
void frmDetailContactToggle::on_btnSearch_clicked()
{
MainWindow *mnWindow = qobject_cast<MainWindow *>(this->parent()->parent()->parent());
QLayoutItem *child;
while ((child = mnWindow->rightPane()->layout()->takeAt(0)) != 0)
child->widget()->setVisible(false);
mnWindow->rightPane()->setVisible(false);
QScrollArea *scrlContent = qobject_cast<QScrollArea *>(mnWindow->tabContentWidget()->currentWidget());
scrlContent->setWidgetResizable(false);
mnWindow->tabContentWidget()->setGeometry(mnWindow->tabContentWidget()->x(), mnWindow->tabContentWidget()->y(), m_width - mnWindow->tabContentWidget()->x() - 10, mnWindow->tabContentWidget()->height());
scrlContent->setWidgetResizable(true);
m_showRightPane = false;
}
I have realized that I can't change the geometry when WidgetResizable is true. It showed "The inferior stopped because it received signal from the Operating System" error. So I thought about making it false, changing the geometry, and making it true again. But when I want to make it true, I encounter the same error. Could anyone please help me to solve my problem?
if your program used uninitialized pointers,that may causes SIGSEGV.

How to make a QMdiArea subwindow widget non-resizeable?

So the non-QMdiArea version of my code,
MyWidget::MyWidget(QWidget* parent)
{
...
layout()->setSizeConstraint( QLayout::SetFixedSize );
}
MainWindow::MainWindow(...)
{
...
MyWidget* wgt = new MyWidget(NULL);
wgt->show();
}
works just fine and produces a widget that the user can't resize. But when the MainWindow code is replaced with
MainWindow::MainWindow(...)
{
...
MyWidget* wgt = new MyWidget(ui->mdiArea); //Or MyWidget(NULL), same result
ui->mdiArea->addSubWindow(wgt);
}
the window, now within the QMdiArea, is resizeable. It doesn't seem to be an issue of Qt::WindowFlags, they don't handle resize policy. Surely there is a way to do this? NB I cant use something like setFixedSize(ht, wd) since the size of the widget can change programmatically (subwidgets are added and removed). But the user should not be able to resize it.
Even though MyWidget is not resizeable, when you call:
ui->mdiArea->addSubWindow(wgt);
The widget is put in a QMdiSubWindow which is resizeable. All you have to do is get the window that's created and fix its size:
QMdiSubWindow* subWindow = ui->mdiArea->addSubWindow(wgt);
subWindow->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
This should work, but I haven't tried this code myself.
EDIT: well... apparently that doesn't fix the size. :(
The following worked for me:
MyWidget* wgt = new MyWidget(ui->mdiArea);
QMdiSubWindow* subWindow = ui->mdiArea->addSubWindow(wgt);
subWindow->setFixedSize(wgt->size());
wgt->show();

Qt - There is a bug in QPropertyAnimation?

I face a very serious situation. By writing this question I hope that really professionals will express their opinion regarding to the problem I am going to describe. I have reported a bug in https://bugreports.qt.io/ :
I have created QPropertyAnimation for maximumWidth property of QTextEdit and it does not work (it immediately changes state from starting state to the end state), though it works for minimumWidth property.
Please see the attached code.
And have attached .h and .cpp files. See those files here (files are named new.h and new.cpp).
And I got the follwing response:
MaximumWidth is not the property you want to animate. It holds the maximum width that the widget can have, it's related to layouting and so on. Changing the maximumWidth (as well as the minimumWidth) does not necessarily trigger a relayout and repaint. You should animate the size.
Please explain me whether it is a bug or no? Please tell me how the minimumWith property is being animated but when it concerns to the maximumWidth property, then I should not work and that is OK? I just don't get their point... Please explain.
P.S. I have written this code because I wanted to close by animation the right QTextEdit and be sure that when I resize the main window, where the button and two QTextEdit are, the closed QTextEdit does not being restored.
Did you check the actual value of maximumWidth? You don't seem to set a specific maximumWidth in your code.
The default value for maximumWidth is 16777215, and you set a duration of 1 msec. for the closing animation. Fading from 16777215 to 3 in 1 msec. would look like "instant", I guess.
I don't think it is a bug; I'd call it "undefined behavior". That means that if you try to animate minimumWidth, nobody can tell you for sure what is supposed to happen, and maybe the code has some optimizations or corner cases where sometimes it works, others it doesn't.
Anyway, minimumWidth and maximumWidth aren't supposed to be used to define what the size of a QWidget is, only what it must not exceed; i.e. they weren't designed to do what you are trying to do, so it can be called a bug. If you want to animate, you have to use a deterministic approach, which in this case is using the geometry property.
This is not a bug, the response you got from the bug report pretty well explains the problem with your code and a solution.
Dear Sofahamster I have changed my code to the code below and it works fine. Thanks for your hint!
Header file
class MyWidget : public QWidget
{
Q_OBJECT
QTextEdit *m_textEditor1;
QTextEdit *m_textEditor2;
QPushButton *m_pushButton;
QHBoxLayout *m_layout;
QVBoxLayout *m_buttonLayout;
int m_deltaX;
bool m_isClosed;
public:
MyWidget(QWidget * parent = 0);
~MyWidget(){}
void resizeEvent( QResizeEvent * event );
private slots:
void closeOrOpenTextEdit2(bool isClosing);
};
Source file
MyWidget::MyWidget(QWidget * parent):QWidget(parent),m_deltaX(0)
{
m_pushButton = new QPushButton(this);
m_pushButton->setText(">");
m_pushButton->setCheckable(true);
m_pushButton->setFixedSize(16,16);
connect(m_pushButton, SIGNAL(clicked(bool)), this, SLOT(closeOrOpenTextEdit2(bool)));
m_textEditor1 = new QTextEdit(this);
m_textEditor1->setText("AAAAA AAAAAAAAAAA AAAAAAAAAAA AAAAAAA AAAAAAAAAAA AAAAAAAAAAA AA");
m_textEditor2 = new QTextEdit(this);
m_buttonLayout = new QVBoxLayout();
m_buttonLayout->addWidget(m_pushButton);
m_buttonLayout->addItem( new QSpacerItem(1, 1, QSizePolicy::Minimum, QSizePolicy::Expanding) );
m_layout = new QHBoxLayout;
m_layout->addWidget(m_textEditor1, 10);
m_layout->addSpacing(15);
m_layout->addLayout(m_buttonLayout);
m_layout->setSpacing(0);
m_layout->addWidget(m_textEditor2, 4);
setLayout(m_layout);
resize(800,500);
}
void MyWidget::closeOrOpenTextEdit2(bool isClosing)
{
m_isClosed = isClosing;
QPropertyAnimation *animation1 = new QPropertyAnimation(m_textEditor2, "maximumWidth");
if(isClosing) //close the second textEdit
{
m_textEditor2->setMaximumWidth(m_textEditor2->width());
int textEdit2_start = m_textEditor2->maximumWidth();
m_deltaX = textEdit2_start;
int textEdit2_end = 3;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText("<");
}
else //open
{
int textEdit2_start = m_textEditor2->maximumWidth();
int textEdit2_end = m_deltaX;
animation1->setDuration(500);
animation1->setStartValue(textEdit2_start);
animation1->setEndValue(textEdit2_end);
m_pushButton->setText(">");
}
animation1->start();
}
void MyWidget::resizeEvent( QResizeEvent * event )
{
if(!m_isClosed)
m_textEditor2->setMaximumWidth( QWIDGETSIZE_MAX );
}