Qt: QFormLayout::addRow(QWidget* label, QWidget* field) not adding a new row - qt

I am trying to add a new row to my QFormLayout after I have loaded two QLineEdits from a file, which works, but when I run my code it doesnt add anything, ot atleast anything that I can see. And I am also not able to add any wigets using QLayout::addWidget(QWidget* widget) anymore, which I used to be able to.
Thanks
The code, where it doesnt work:
void Kegelbuch::load(QString path, QString tab) {
//Load json file
Datastream* loadStream = new Datastream;
QJsonObject data = loadStream->loadData(path);
//Declaring all important Variables
QJsonArray keglerFullName;
QJsonArray keglerShortName;
QFormLayout* formLayout = (QFormLayout*)ui.keglerTab->layout();
int defaultRows = 2, width = 155;
//Retriev arrays from file
if (data.contains("KeglerFullName") && data["KeglerFullName"].isArray()) {
keglerFullName = data["KeglerFullName"].toArray();
}
if (data.contains("KeglerShortName") && data["KeglerShortName"].isArray()) {
keglerShortName = data["KeglerShortName"].toArray();
}
//Correctly add QLineEdits to the FormLayout
for (auto names : boost::combine(keglerFullName, keglerShortName)) {
QLineEdit fullNameEdit;
QLineEdit shortNameEdit;
QJsonValue fullNameValue, shortNameValue;
boost::tie(fullNameValue, shortNameValue) = names;
if (fullNameValue.isString()) {
fullNameEdit.setText(fullNameValue.toString());
fullNameEdit.setObjectName("fullName");
fullNameEdit.setMinimumWidth(width);
}
if (shortNameValue.isString()) {
shortNameEdit.setText(shortNameValue.toString());
shortNameEdit.setMaximumWidth(width);
shortNameEdit.setObjectName("shortName");
}
/*
if (keglerFullName.at(1).isString()) {
fullNameEdit->setText(keglerFullName.at(1).toString());
fullNameEdit->setObjectName("fullName");
fullNameEdit->setMinimumWidth(width);
}
if (keglerShortName.at(1).isString()) {
shortNameEdit->setText(keglerShortName.at(1).toString());
shortNameEdit->setMaximumWidth(width);
shortNameEdit->setObjectName("shortName");
}
*/
formLayout->addRow(&fullNameEdit, &shortNameEdit);
}
}

Related

How to pin a tab in Qt

Is it possible to pin a tab with Qt?
I want a tab to always stay in place (index 0) while still able to move other tabs.
So far I tried to listen to QTabBar::tabMoved and revert the move but that's too late. I don't want it even to attempt to move.
Worst case for me would be to be forced to change the mouse handling. Let me know please if there is an other way.
I have never found a nice way to do that. But, I used the fact that you can store raw data in the QTabBar to pin the tabs and undo a move if it was a pinned tab. It's not perfect and I still have some ugly behavior, but I didn't want to use mouse events, neither.
First, create a struct to store the current state of a tab:
struct PinnedTab
{
bool isPinned;
int currentIndex;
};
Q_DECLARE_METATYPE(PinnedTab); // For QVariant
Then, create a custom QTabBar to handle the move and use QTabWidget to replace the current tab bar (you have to do that before inserting the tabs):
class Bar: public QTabBar
{
public:
void pin(int const index)
{
PinnedTab info;
info.isPinned = true;
info.currentIndex = index; // TODO: move the tab to the left and do not use current index
setTabData(index, QVariant::fromValue(info));
}
Bar(QWidget* parent=nullptr): QTabBar(parent)
{}
virtual void tabLayoutChange() override
{
for (int i = 0; i != count(); ++i) // Check if a pinned tab has moved
{
if (tabData(i).isValid())
{
PinnedTab const info = tabData(i).value<PinnedTab>();
if (info.isPinned == true && i != info.currentIndex) {
rollbackLayout();
return;
}
}
}
for (int i = 0; i != count(); ++i)
{
if (tabData(i).isValid())
{
PinnedTab info = tabData(i).value<PinnedTab>();
info.currentIndex = i;
setTabData(i, QVariant::fromValue(info));
}
else
{
PinnedTab info;
info.isPinned = false;
info.currentIndex = i;
setTabData(i, QVariant::fromValue(info));
}
}
}
void rollbackLayout() {
for (int i = 0; i != count(); ++i)
{
if (tabData(i).isValid())
{
PinnedTab const info = tabData(i).value<PinnedTab>();
if (i != info.currentIndex) {
moveTab(i, info.currentIndex);
}
}
}
}
};
tabLayoutChange is called when the layout has changed. So, it will be called when you move a tab.
the rollbackLayout method is used to move each tab to the last position stored in the tab data.
Call pin to pin a tab with the given index.
I simplified my code for more clarity and you may have to redefine some behavior (for now, if you pin a tab, it will keep its current position and it will not handle the insert/remove tabs).

Display gif only once

I'm using gifs in my app. I'd like to only show my gif once and then make it disappear. But it keeps looping and showing again and again.
Here's what I've tried:
movie = new QMovie(":/in_game/src/countdown.gif");
processLabel = new QLabel();
this->addWidget(processLabel);
processLabel->setStyleSheet("background-color: rgba(0,0,0,0%)");
processLabel->setGeometry(280,250,128,128);
processLabel->setMovie(movie);
int i=0;
if(i<1)
{
movie->start();
i++;
}
else
{
movie->stop();
processLabel->setEnabled(false);
}
Of course in my .h I've created a QMovie and a QLabel... Any ideas on how to only display once ?
You have QMovie::frameCount() method and signal QMovie::frameChanged(). Check your current frame number and stop when current frame become equal QMovie::frameCount()
m_movie = new QMovie(":/gif/tenor.gif");
connect(m_movie, SIGNAL(frameChanged(int)),
this, SLOT(OnFrameChanged(int)));
ui->lblMovie->setMovie(m_movie);
m_movie->start();
And in slot:
void MainWindow::OnFrameChanged(int frame)
{
if (frame == m_movie->frameCount() - 1) {
m_movie->stop();
}
}

Level as list in QtreeWidget

I have vector with 6 numbers, which I want insert to list and add this list to QTreeWidget. First number of list is on "root" level and other numbers are sublevel "root".
I don't know how to do it.
Image with describe:
Code:
void modal::zapis() {
ui->listWidget->clear();
ui->treeWidget->clear();
QList<QTreeWidgetItem *> items;
for(int i=0;i<v.size();i++)
{
QString string;
string.setNum(v.at(i));
ui->listWidget->addItem(string);
QTreeWidgetItem *root = new QTreeWidgetItem(ui->treeWidget);
if(i==0)
{
root->setText(0, string);
}
else
{
QTreeWidgetItem *item = new QTreeWidgetItem(root);
item->setText(0, string);
}
}
}
Thank you for any ideas.
You are creating a new root node on every iteration, it just needs creating once per call.

QlineEdit with some default text for which cursor should not be moved?

In QT, a created lineEdit shows a text using the setText() method.
But the cursor is movable for the default text. I want the cursor should not be movable for the default text.
My lineEdit type has been set as password. Hence the default text('Password') is also displayed as '********'. Whenever user types the type has to be changed as password and when there is no text or until the user have not typed any text, the lineEdit should display the plain text 'password'
Any idea to fix the above two issues?
In the constructor put
ui->lineEdit->setPlaceholderText("password");
ui->lineEdit->setReadOnly(1);
And in on_lineEdit_selectionChanged() SLOT, put
ui->lineEdit->setText("");
ui->lineEdit->setEchoMode(QLineEdit::Password);
ui->lineEdit->setReadOnly(0);
I noticed this question has tag pyqt so I'll put an actual answer related to that tag for those actually looking for a python way instead of c++.
self.searchEditText = QtGui.QLineEdit()
self.searchEditText.setPlaceholderText("Search for word")
I managed to do what you want by deriving a class from QLineEdit as per following..
Constructor..
QCustomLineEdit::QCustomLineEdit(QWidget *parent) :
QLineEdit(parent)
{
connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));
connect(this, SIGNAL(cursorPositionChanged(int,int)), this, SLOT(onCursorPositionChanged(int,int)));
setEchoMode(QLineEdit::Password); // Echo mode in your case..
m_echoMode = echoMode(); // Member variable to store original echo mode..
m_placeHolderText = "Password"; // Member variable..
m_isPlaceHolderActive = true; // Member varible..
// Default case..
setPlaceholderText("");
setStyleSheet("QCustomLineEdit{color: gray;}");
setEchoMode(QLineEdit::Normal);
setText(__placeHolderText);
}
Override keyPressEvent..
void QCustomLineEdit::keyPressEvent(QKeyEvent *e)
{
if(m_isPlaceHolderActive)
{
if(e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace)
e->accept();
else
QLineEdit::keyPressEvent(e);
return;
}
QLineEdit::keyPressEvent(e);
}
Cursor position change event..
void QCustomLineEdit::onCursorPositionChanged(int /*oldPos*/, int newPos)
{
if(m_isPlaceHolderActive)
{
if(newPos != 0)
setCursorPosition(0);
}
}
Text change event..
void QCustomLineEdit::onTextChanged(const QString &text)
{
if(m_isPlaceHolderActive)
{
if(text.compare(m_placeHolderText) != 0)
{
m_isPlaceHolderActive = false;
// Remove the 'placeHolderText' from 'text' itself..
QString temp = text;
temp = temp.mid(0, text.lastIndexOf(m_placeHolderText));
setStyleSheet("QCustomLineEdit{color: black;}");
setEchoMode(m_echoMode);
setText(temp);
}
else
{
setEchoMode(QLineEdit::Normal);
setText(m_placeHolderText);
setStyleSheet("QCustomLineEdit{color: gray;}");
setCursorPosition(0);
}
}
else
{
if(text.isEmpty())
{
m_isPlaceHolderActive = true;
setStyleSheet("QCustomLineEdit{color: gray;}");
setEchoMode(QLineEdit::Normal);
setText(m_placeHolderText);
}
}
}
I have written it very hastily to just show you. Test it yourself and feel free to point any mistake(s) or optimization(s). Hope this helps.
For question 1, in Qt 5.0 and higher, setPlaceholderText does what you want. https://codereview.qt-project.org/#change,45326

HowTo find Subitem in QAbstractItemModel and QTreeView class?

Question: how to find sub item, in a QTreeView loaded QAbstractItemModel model with model->match() method?
Problem: model->match() can't find sub items, wtf?!
Here is the example:
As you can see from the picture, I'm trying to expand Layouts sub item with this code:
void Dialog::restoreState(void)
{
// get list
QSettings settings("settings.ini", QSettings::IniFormat);
settings.beginGroup("MainWindow");
QStringList List = settings.value("ExpandedItems").toStringList();
settings.endGroup();
foreach (QString item, List)
{
if (item.contains('|'))
item = item.split('|').last();
// search `item` text in model
QModelIndexList Items = model->match(model->index(0, 0), Qt::DisplayRole, QVariant::fromValue(item));
if (!Items.isEmpty())
{
// Information: with this code, expands ONLY first level in QTreeView
view->setExpanded(Items.first(), true);
}
}
}
Where settings.ini file contains:
[MainWindow]
ExpandedItems=Using Containers, Connection Editing Mode, Form Editing Mode, Form Editing Mode|Layouts
PS: root items successfully expands on start!
Here is the solution:
QModelIndexList Items = model->match(
model->index(0, 0),
Qt::DisplayRole,
QVariant::fromValue(item),
2, // look *
Qt::MatchRecursive); // look *
* Without that argument match() function searches only 1 level
My working example on QTreeView.
QModelIndexList Indexes = this->ui->treeView->selectionModel()->selectedIndexes();
if(Indexes.count() > 0)
{
QStandardItemModel *am = (QStandardItemModel*)this->ui->treeView->model();
QStack<QModelIndex> mis;
QModelIndex mi = Indexes.at(0);
while(mi.isValid())
{
mis.push(mi);
mi = mi.parent();
}
QStandardItem *si;
bool FirstTime = true;
while (!mis.isEmpty())
{
mi = mis.pop();
if(FirstTime)
{
FirstTime = false;
si = am->item(mi.row());
}
else
{
si = si->child(mi.row());
}
}
// "si" - is selected item
}
Wanted to add to the answer that #mosg gave
The forth parameter is actually the hits parameters.
It decides ho many matches one wants to return.
For all matches specify -1 as can be seen
here:
QModelIndexList Items = model->match(
model->index(0, 0),
Qt::DisplayRole,
QVariant::fromValue(item),
-1, // any number of hits
Qt::MatchRecursive); // look *

Resources