Setting the Height of a QPlainTextEdit Delegate in a QTableView - c++

I'm working here on a project and currently I'm stuck on the following problem.
It is about a QTableView which has a column called "Description", the cells of this column contain a QPlainTextEditDelegate. I'm failing on setting the Height of the QPlainTextEdit everytime it is entered. Right now it behaves like a QLineEdit until I drag the row ( in which I'm active at that time ) of the QTableView larger.
What I want to do is to change the Height of the QPlainTextEdit once I entered it.
What are your suggestions? How can I proceed to get this thing done?
Thank you all in advance!
BTW Sorry for my poor english :/
edit:
Ok I solved it, but without sizeHint, I used updateEditorGeometry :
void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
And inside this Method, you can set the width or height like you want
editor->setGeometry(option.rect.x(),option.rect.y(),<your_width>,<your_height>);
But thank you anyway!

You should reimplement QAbstractItemDelegate::sizeHint method to return expected height when you create your editor. I don't think that it's necesary to emit QAbstractItemDelegate::sizeHintChanged signal after creating editor, but documentation doesn't say anything. If it doesn't work without it, you should emit sizeHintChanged after returning created editor widget to notify view of need to change row height.

Related

Problems with QTreeWidget

Good morning, I am learning about programming and GUI in Qt c++ and I have some doubts:
Let's suppose you have this GUI shown in the picture. No worries about how has it been created. It has:
QTreeWidget
QLineEdit
QPushButton1
QPushButton2
How would you make the following things?
When clicking on a name or in a value, to make that only the value of this row appear in the QLineEdit
In the next example, I have been able to show the name or the value, but I only want the value to be shown, even if the name has been clicked.
void MainWindow::on_treeView_activated(const QModelIndex &index)
{
QString val = ui->treeView->model()->data(index).toString();
ui->lineEdit->setText(val);
}
If I change the value of the QLineEdit and then click the QPushButton1, the QTreeWidget should be updated with this new value.
If I click the QPushButton2, save "the names = the values" into a .txt file
(FUTURE) I want to have these 3 point clear first. Then, my goal is to make the same with this picture:
Thanks a lot in advance!

Open a new window when a particular cell of a row in a QTableView is clicked in Qt

I have a table which displays some dynamic data. I need to implement a feature whereby if the user clicks a designated column of the row (note that this particular column doesn't need to display any data. It is simply needs to function as a place to receive this special user input (a click is what I have in mind)), I should be able to open a new window. Note that this new window DOES not need to edit the contents of the table at all.. In fact it will display some other contextual data which is not present in the table itself.
How do I implement this in Qt?
Use Signals and slots. Hope this will be helpful!
connect(tableView,SIGNAL(clicked(const QModelIndex &)),this,SLOT(function(const QModelIndex &)));
void function(const QModelIndex &index)
{
int row=index.row();
int column=index.column();
dialog->show();
//do the stuff
}

How to draw a custom control in QTableView?

I have to draw a custom control in QTableView. This control must looks like FileChooser.
FileChooser http://www.vision.ee.ethz.ch/computing/sepp-irix/qt-3.0-mo/filechooser.png
QStyleOptionButton button_option;
button_option.state |= QStyle::State_Enabled | QStyle::State_Off;
button_option.rect = PushButtonRect(option); //calculate button rect
button_option.text = "...";
QApplication::style()->drawControl(
QStyle::CE_PushButton,
&button_option,
painter);
The code above draws QStyle::CE_PushButton - that looks like QButton, - but there is no QStyle::CE_LineEdit in Qt library. How can I draw QLineEdit?
In order to draw custom widgets in a Table View, you need to create a custom QItemDelegate subclass and override at least the createEditor method, where you can create any kind of widget which is displayed when double-clicking into the table cell. This item delegate can be assigned to the respective column in your table view.
You would then need to create a separate class e.g. CustomFileChooser which inherits from QWidget and consists of a Line Edit and Button.
Your createEditor method would then return such an object.
You may also have to override setEditorData (which shall assign the current model value to the editor widget which was created) and setModelData (which is called when the changes are committed).
This way, the line edit and button would only be visible after double-clicking into the table cell. If you want it to be always visible, you will have to override drawDisplay() as well.
I found an answer by myself. You may display a custom editor (ordinary widget) permanently using:
void QAbstractItemView::openPersistentEditor ( const QModelIndex & index )
First you need to understand that a button is a control Element and thus you can find it under CE but when you need a lineEdit it is not a control element.
In order to paint a lineEdit, I shall quote from the qt documentation,
"QStyleOptionFrameV2 inherits QStyleOptionFrame which is used for drawing several built-in Qt widgets, including QFrame, QGroupBox, QLineEdit, and QMenu."
Yes, only a sample code that might work will help you understand it clearly!
The code should somehow look like this
QStyleOptionFrameV2 *panelFrame = new QStyleOptionFrameV2;
QLineEdit *search = new QLineEdit;
panelFrame->initFrom(search);
panelFrame->rect = QRect(x,y,w,h);//Indeed the location and the size
panelFrame->lineWidth = QApplication::style->pixelMetric(QStyle::PM_DefaultFrameWidth, panelFrame, search);
panelFrame->state |= QStyle::State_Sunken;
QApplication::style()->drawPrimitive(QStyle::PE_PanelLineEdit, panelFrame, painter);

QStyledItemDelegate's sizeHint method not called for a QTableView row

I have QTableView using a QSqlQueryModel (it fetches data from SQLite).
There is a QStyledItemDelegate subclass called MiniItemDelegate that I use as a delegate for the items. I set up a sizeHint() method like this:
QSize MiniItemDelegate::sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
// just for testing...breakpoint shows this line never gets called
return QSize(256,256);
}
I'm not sure why this method isn't called when I run the following code:
m_pMiniItemDelegate = new MiniItemDelegate(this);
ui->PList_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->PList_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->PList_tableView->setItemDelegate(m_pMiniItemDelegate);
ui->PList_tableView->setAlternatingRowColors(true);
ui->PList_tableView->setModel(ListMiniSqlModel::instance());
This also doesn't work:
ui->PList_tableView->resizeColumnsToContents();
ui->PList_tableView->resizeRowsToContents();
Nor does this:
QHeaderView* headerView = ui->PList_tableView->horizontalHeader();
headerView->setResizeMode(QHeaderView::ResizeToContents);
QStyledItemDelegate::sizeHint is useful only when QTableView::resizeRowsToContents, QTableView::resizeRowToContents, QTableView::resizeColumnsToContents and QTableView::resizeColumnToContents are called. or use
QHeaderView* headerView = tableView->horizontalHeader();
headerView->setResizeMode(QHeaderView::ResizeToContents);
Have you tried: setColumnWidth or setRowHeight and horizontalHeader()->setResizeMode(QHeaderView::Fixed) ?
(Credit where credit is due.)
In #HostileFork's comment about a Qt Forum discussion, there's a comment thread. Within that thread, a user mikhailt offers a good solution.
The verticalHeader has a DefaultSectionSize property that can be adjusted. It doesn't matter whether the vertical header (labels on the left side of the table) is actually being displayed or not, the size will still be used.
ui->PList_tableView->verticalHeader()->setDefaultSectionSize(34);
This just solved my problem with Qt 5.6, and saved me from adjusting each data row's height separately, or causing a resize on a table.
Based on the age of the comment thread where I found it, this was already working in Qt 4, too.

Which model to subclass / view to use for a list of custom objects

I don't have enough experience with Qt yet to make a good design choice. Any help by experienced Qt programmers would be very appreciated.
I'm trying to find out which model to subclass, which view to use, what delegate subclassing / extending I should do...
My problem is similar to: I have these zones I would like to display, 1 per row:
class Zone{
//inputs
string country; //edited with a QComboBox
string city; //edited with a QComboBox
int ageMin;
//stored result
int nbInhabitantsOlderThanMin;
}
Here's what I'd like to do, and the design choices each requirements makes me think of:
I would like to display a list of them (--> QListView )
But to display 1 item I need several columns (--> QTableView )
I would like a double click on a row to trigger editing in a custom widget, since nbInhabitantsOlderThanMin can not be edited, and choosing a country restricts the list of cities that can be chosen in the QComboBox (and vice versa in my real example) (--> I should probably use a QDataWidgetMapper (or subclass?) somewhere...)
So whereas the edition of a row should happen in a widget, the display is simple / not custom, and subclassing a delegate (QStyledItemDelegate for instance) (I'm not so sure about this one) doesn't seem to be the right way to have 1 custom widget with many child input widget to edit the 3 fields at the same time.
I think the data to model would favor a model subclassing QAbstractListModel, but the display with many columns compatible with default delegate viewing favors a QAbstractTableModel..
So I don't really know which design to go for. Any experienced help connecting the dots is very welcome :)
QDataWidgetMapper is a slightly different thing. It is a way to display one item from a Model (ex. QStandardItemModel), using custom controls. You can read more about it here, with accompanying snapshots and an example of how to implement one.
While it is certainly cool, I don't think it is what you want here. Mostly because you specified that you want to view your items in a list format. However, you could display all your items in a simple list, double-click which would open a dialog using the QDataWidgetMapper. In which case all you would need to do with a QListView/QListWidget is implement the double-click event.
Still, I personally don't like the added burden of the extra window on a user. I prefer to use popups sparingly. But if you like that approach, then go ahead. This is another example of the QDataWidgetMapper which is pretty nice.
My preferred approach is still to use the QTableView, and provide delegates for the columns that need specialized editing. Here is a great walk-through of all things Model/View. So if you decide to use the QListView or QTableView it will give you a great start. It also talks about how you can create delegates to edit fields however you want.
So, how do you create a custom delegate? Basically, you just inherit from QItemDelegate. There are some examples in the link above, but I'll highlight a few salient points.
QWidget *ComboBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &index) const
{
QComboBox *editor = new QComboBox (parent);
// Add items to the combobox here.
// You can use the QModelIndex passed above to access the model
// Add find out what country was selected, and therefore what cities
// need to be listed in the combobox
return editor;
}
void ComboBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QComboBox *comboBox= static_cast<QComboBox *>(editor);
int _SelectedItem = // Figure out which is the currently selected index;
comboBox->setCurrentIndex(_SelectedItem);
}
void ComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QComboBox *comboBox= static_cast<QComboBox *>(editor);
comboBox->interpretText();
int value = comboBox->currentIndex();
// Translate the current index to whatever you actually want to
// set in your model.
model->setData(index, value, Qt::EditRole);
}
Fill in the gaps that I left in my example and you have your Delegate.
Now, how to use this in your QTableView:
You can set a delegate for a particular column of your table as follows:
setItemDelegateForColumn(_ColumnIndex, new ComboBoxDelegate(_YourTableModel));
And, if you want to prevent certain columns from being editable:
_YourTableModel->setColumnEditable(_ColumnIndex, false);
Once you have your model set up, everything else should take care of itself.
Hope that helps.
First, you should subclass QAbstractItemDelegate (or QItemDeleage, that could be more convenient), where reimplement createEditor, setEditorData and setModelData.
Than, you should set your own itemDelegate (see QAbstractItemView::setItemDelegate).
It's commonly no difference, what widget to use to present data: It could be either QTreeWidet, or QTreeView, or QTableWidget, or QTableView. Note, that "widgets" are easier to use, than "views", but they are not so powerfull
I just finished something very similar to this in that I needed multiple fields for each object which I wanted in a row. The way I did it, which worked out very well, was to subclass QAbstractListmodel and use a custom ListItem. I kind of faked the columns by having a custom delegate and using some javascript to figure out the size of the largest thing in each field, and then set the column size to that width. I think this is the easiest way of doing it.
For the comment below, zone would inherit from:
class ListItem: public QObject {
Q_OBJECT
public:
ListItem(QObject* parent = 0) : QObject(parent) {}
virtual ~ListItem() {}
virtual QString id() const = 0;
virtual QVariant data(int role) const = 0;
virtual QHash<int, QByteArray> roleNames() const = 0;
signals:
void dataChanged();
};