How get coordinates of widget in qgrid layout in Qt - qt

I am trying to design a sudoku game with a grid layout full of qpushbuttons, At the momment of inserting a number in of the qpush button whihch is triggered when clicking on them I need to check if its a valid move depending on the other "cells". My problem is that i need the row and column of the qpushbutton that was clicked in qgridlayout but havent been able to find how to do it. Is there some way to obtain the coordinates of the qpushbutton clicked on the qgridlayout?

http://doc.qt.io/qt-4.8/layout.html#horizontal-vertical-grid-and-form-layouts
http://doc.qt.io/qt-4.8/qgridlayout.html#getItemPosition
http://doc.qt.io/qt-4.8/qlayout.html#indexOf
Your code should look something like:
int index = my_grid_layout->indexOf(clicked_widget);
if(index != -1)
{
int row, col, col_span, row_span;
my_grid_layout->getItemPosition(index, &row, &col, &col_span, &row_span);
qDebug() << "Clicked Item is at:" << row << col
<< "spanning" << row_span << col_span;
}
Hope that helps.

Related

Best way to make grid with custom amount of square items in QT

I want to create a custom size grid of squares where user can choose how many columns and rows are in the gird. The sqaures in the grid must be clickable so that they can change color when user clicks them. The grid is ment for pathfinding visalization.
I thought about using QRect that are stored in some kind of map with coordinates or QGraphicsItem in QGraphicsScene. What is the best QT class for this considering performance because i'm not sure if getting the postion of click in mouse event and then looping through huge grid is the best way?
Thank you in advance.
If I were you, I would just put QPushButtons into a QGridLayout. They are clickable and then you can change the colour accordingly.
QGridLayout *buttonLayout = new QGridLayout(this);
size_t rows = 5, columns = 5; // You can make this configurable.
for (size_t row = 0; row < rows; ++row) {
for(size column = 0; column < column; ++column) {
QPushButton *button = new QPushButton;
connect(button, &QPushButton::clicked, this, [this](){/* change colours */});
buttonLayout->addWidget(button, row, column);
}
}
centralWidget->setLayout(buttonLayout);

Qt connect QScrollBar with QLineEdit

I would like to "activate" the scrollbar when the lineedit text is too long to display on the window. I have already done it.
I want to move the cursor with the scrollbar. I also want to modify the scroll bar slider length with the increment/decrement of the text length.
.h
private:
Ui::MainWindow *ui;
QLineEdit* LineEdit;
QScrollBar* hScrollBar;
void HDScrollBar();
constructor:
resize(400,100);
LineEdit = new QLineEdit(this);
LineEdit->resize(400,100);
LineEdit->setFont(QFont("Times",20));
hScrollBar = new QScrollBar(Qt::Horizontal, LineEdit);
hScrollBar->resize(400,20);
hScrollBar->move(0,80);
hScrollBar->hide();
connect(LineEdit, &QLineEdit::textChanged, this, &MainWindow::HDScrollBar);
hide/display scrollbar
void MainWindow::HDScrollBar() {
QFont myFont(QFont("Times",20));;
QString str = LineEdit->text();
QFontMetrics fm(myFont);
int width = fm.horizontalAdvance(str);
(width >= 400) ? hScrollBar->show() : hScrollBar->hide();
}
As for the first part, you use can scrollbar's valueChanged signal, e.g. this way:
connect(ui->horizontalScrollBar, &QScrollBar::valueChanged, ui->lineEdit, [&](int v) {
auto scrollbarAt = static_cast<double>(v) / ui->horizontalScrollBar->maximum();
auto cursorTo = std::round(ui->lineEdit->text().length() * scrollbarAt);
ui->lineEdit->setCursorPosition(cursorTo);
});
EDIT:
as for the latter part:
you can either alter the PageStep of the scrollbar, or you can set it to 1 and alter its maximum value, then also the first part should simplify:
ui->horizontalScrollBar->setPageStep(1);
ui->horizontalScrollBar->setMaximum(ui->lineEdit.text().length());
connect(ui->horizontalScrollBar, &QScrollBar::valueChanged,
ui->lineEdit, &QLineEdit::setCursorPosition);
//this can also ben done on textChanged, however for the price
//of more frequent execution...
connect(ui->lineEdit, &QLineEdit::cursorPositionChanged,
ui->horizontalScrollBar, [&](int, int n) {
ui->horizontalScrollBar->setMaximum(ui->lineEdit->text().length());
//...one gets the easy way to track the cursor
//with the slider
ui->horizontalScrollBar->setValue(n);
});

Dragged QGraphicsItem not visible in items() function

I have created a QGraphicsScene scene and added some graphcis items (lines, rectangles) etc to the scene.
I can loop through them using this list :
QList<QGraphicsItem*> all = items();
I enabled movement for these items and I am able to drag them by click selecting them. But after an element has been dragged, it stops showing up in the call to items() function of the QGraphicsScene.
QList<QGraphicsItem*> all = items();
None of the dragged items show up in the above list, while non-dragged ones do show up.
Does dragging the QGraphicScene elements change their parent ? or any other reason somebody could suggest for such an issue ?
{P.S. Code is too very big to share}
Edit 1 :
I am using the flags QGraphicsItem::ItemIsSelectable and QGraphicsItem::ItemIsMovable for making the items movable.
foreach(QGraphicsItem* itemInVisualScene, items())
{
itemInVisualScene->setFlag(QGraphicsItem::ItemIsSelectable, itemsMovable);
itemInVisualScene->setFlag(QGraphicsItem::ItemIsMovable, itemsMovable);
}
By default I add few rectangle to the scene. Then in the 'move mode' I drag them around. Then in the 'add mode' I click on screen to add new rectangles. I have written a logic to check if I am clicking on any existing drawn rectangle :
void Scene::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
if(eDrawLines == sceneMode)
{
dragBeginPoint = event->scenePos();
dragEndPoint = dragBeginPoint;
QList<QGraphicsItem*> all = items();
for (int i = 0; i < all.size(); i++)
{
QGraphicsItem *gi = all[i];
// Clicked point lies inside existing rect
if( QGraphicsRectItem::Type == gi->type() && gi->contains(dragBeginPoint))
{
std::cout << "Pressed inside existing rect" << std::endl;
return;
}
}
std::cout << "Point not found, add new rectangle" << std::endl;
}
QGraphicsScene::mousePressEvent(event);
}
This adding of rectangles work fine for rects which were not dragged in the 'move mode'. But rects which were moved do not seem to recognize the click anymore. My control comes out of the loop even when I click on an existing rectangle which was dragged earlier.
QGraphicsItem's transform is changed after dragging and therefore need to transform the point to item's local coordinates.
gi->contains(gi->mapFromScene(dragBeginPoint))
To convert or get item's position in scene coordinates, use
gi->mapToScene(0,0) or gi->scenePos()

Qt: Visibility state of the QWidget when used stylesheet

I have customized QWidget named "MainWidget" and a customized QWidget named "ChildWidget".
MainWidget is the parent of ChildWidget and these child widgets are created dynamically and inserted into the MainWidget's stack of widgets.
I have used style sheet to set the background color of the both MainWidget and ChildWidget in their respective .ui (form) file.
Select the widget ->Right Click on Widget-> Change stylesheet -> select background color-> apply -> save the .ui file
"background-color: ;"
Each ChidlWidget has its own unique size (width & height) such that when they have stacked on MainWidget's stack of widgets, there may be chances of one widget overlapping other widget, some widgets are completely obscured and some widgets are partially visible.
I am trying to find the visibility state of all types of widgets ( obscured, completely visible , partially visible) .
I am using following code snippet.
void MainWidget::printVisibilityState()
{
QList<ChildWidget *> childWidgetsList = findChildren<ChildWidget *>();
for (register int i = 0; i < childWidgetsList.size(); i++)
{
ChildWidget* pWidget = childWidgetsList.at(i);
QRegion visibleRegion = pWidget->visibleRegion();
QRect visibleRegionBoundingRect = visibleRegion.boundingRect();
int visibleRegionRectsCount = visibleRegion.rects().count();
QRect widgetRect = pWidget->rect();
if (visibleRegion.isEmpty()) {
qDebug() <<pWidget->getName()<< "is OBSCURED";
}
else {
if (
(visibleRegionBoundingRect == widgetRect) &&
(1 == visibleRegionRectsCount))
{
qDebug() <<pWidget->getName()<< "is VISIBLE";
}
else
{
qDebug() <<pWidget->getName()<< "is PARTIALLY VISIBLE";
}
}
}
}
and I have implemented painEvent in both MainWidget and ChildWidget with the following code snippet.
void ChildWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
void MainWidget::paintEvent(QPaintEvent *)
{
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
This code prints the visibility state for all child widgets as VISIBLE always.
Note: Instead of setting the background-color using style sheet, if I use the setAutoFillBackground(true) for both MainWidget and ChildWidget then I am getting the proper visibility state.
Could you please guide me why it doesn't get me the proper visibility state when used style sheet?
Am I missing something in calculating the visibility state?
Are there any other way to get the visibility state info?
The QWidget document (http://qt-project.org/doc/qt-4.8/qwidget.html#visible-prop) says that, "A widget that happens to be obscured by other windows on the screen is considered to be visible."
If this is the case How do we determine the visibility state for the partially visible widgets? ( For example an error popup on other window, so error popup is completely visible and window is partially visible)
Please help me
Regards
SRaju

ComboBox of CheckBoxes?

I am trying to make the items in a ComboBox checkable. I tried this:
http://programmingexamples.net/wiki/Qt/ModelView/ComboBoxOfCheckBoxes
where I subclassed QStandardItemModel and re-implemented the flags() function to make the items checkable. Then I added this model to the ComboBox. Unfortunately, a checkbox does not appear with the items. Can anyone see where I have gone wrong?
Have you set a check state as well as making them checkable?
In my example below, this line is critical:
item->setData(Qt::Unchecked, Qt::CheckStateRole);
If it is omitted the check boxes won't render as there isn't a valid check-state to render.
The example shows check boxes in a combobox, list and table, as I couldn't get it to work at first either, so I tried different views.
test.cpp
#include <QtGui>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QStandardItemModel model(3, 1); // 3 rows, 1 col
for (int r = 0; r < 3; ++r)
{
QStandardItem* item = new QStandardItem(QString("Item %0").arg(r));
item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
item->setData(Qt::Unchecked, Qt::CheckStateRole);
model.setItem(r, 0, item);
}
QComboBox* combo = new QComboBox();
combo->setModel(&model);
QListView* list = new QListView();
list->setModel(&model);
QTableView* table = new QTableView();
table->setModel(&model);
QWidget container;
QVBoxLayout* containerLayout = new QVBoxLayout();
container.setLayout(containerLayout);
containerLayout->addWidget(combo);
containerLayout->addWidget(list);
containerLayout->addWidget(table);
container.show();
return app.exec();
}
test.pro
QT=core gui
SOURCES=test.cpp
I have a little addition.
If one compiles the skyhisi's code then the combobox on Mac OS X
doesn't look as combobox with native checkboxes. You can see it
on the screenshot.
Tested with qt-4.8.5 and 5.1.1.
It seems like Qt draws these controls by itself. Our team has
found the following workaround by pure accident. You can subclass QStyledItemDelegate and reimplement paint() this way:
void SubclassOfQStyledItemDelegate::paint(QPainter * painter_, const QStyleOptionViewItem & option_, const QModelIndex & index_) const
{
QStyleOptionViewItem & refToNonConstOption = const_cast<QStyleOptionViewItem &>(option_);
refToNonConstOption.showDecorationSelected = false;
//refToNonConstOption.state &= ~QStyle::State_HasFocus & ~QStyle::State_MouseOver;
QStyledItemDelegate::paint(painter_, refToNonConstOption, index_);
}
You can then set this delegate to the combo box by adding the following lines to skyhisi's code:
SubclassOfQStyledItemDelegate *delegate = new SubclassOfQStyledItemDelegate(this);
combo->setItemDelegate(delegate);
The comboBox installed with this delegate looks the following way:
On Windows there may be a different issue: text of the checkBoxes has sticked background or dotted border around an item:
To change this appearance one can add the following line to the overridden paint just
before the line QStyledItemDelegate::paint(painter_, refToNonConstOption, index_)
(in the code sample this line was commented):
refToNonConstOption.state &= ~QStyle::State_HasFocus & ~QStyle::State_MouseOver;
Result:
You can try this with QListView:
QStringList values = QStringList << "check 1" << "check 2" << "check 3" << "check 4";
QStandardItemModel model = new QStandardItemModel;
for (int i = 0; i < values.count(); i++)
{
QStandardItem *item = new QStandardItem();
item->setText(values[i]);
item->setCheckable(true);
item->setCheckState(Qt::Unchecked);
model->setItem(i, item);
}
ui->list->setModel(model);
I tried to make this example on Linux Mint, but I can't make the checkboxes visible.
I had to implement the SubclassOfQStyledItemDelegate class and set the delegate to the checkbox as Neptilo and gshep advised.

Resources