I have an HBoxLayout with different QLabels inside. I want to loop through all those QLabels and set the text to an empty string. I tried the following, but nothing happens:
void MainWindow::addLabelItem() {
const QList<QLabel*> labels = ui->hBoxLabels->findChildren<QLabel*>();
for (QLabel *label : labels) {
if (label->text() == "Head") {
label->setText("");
}
}
ui->hBoxLabels->addWidget(new QLabel("Head"));
}
Where do I go wrong? Thanks :)
I figured out the solution:
void MainWindow::addLabelItem() {
for (int i = 0; i < ui->hBoxLabels->count(); ++i) {
QLayout *layout = ui->hBoxLabels->layout();
QLabel *label = qobject_cast<QLabel*>(layout->itemAt(i)->widget());
if (label->text() == "Head") {
label->setText("");
}
}
ui->hBoxLabels->addWidget(new QLabel("Head"));
}
Related
Im trying to create an tic tac toe game, where buttons are used for the positions of where the knaughts and crosses are to be used. When I move the buttons into their respective places, the slot is not triggered and nothing happens.
`
#include "tic_tac_toe.h"
#include <iostream>
tic_tac_toe::tic_tac_toe(QWidget *parent)
: QMainWindow(parent)
{
setFixedSize(900,900);
initBoard();
//showBoard();
connect(button,SIGNAL(clicked()),this,SLOT(buttonpressed()));
}
tic_tac_toe::~tic_tac_toe()
{
}
void tic_tac_toe::initBoard()
{
int x = 0;
int y = 0;
for(int i = 0; i < 10; i++)
{
button = new QPushButton(this);
board.append(button);
button->show();
button->setFixedSize(300,300);
//button->setStyleSheet("border: 5px solid black");
button->setText("??");
// button->move(x,y);
// x = x + 300;
// if(x == 900)
// {
// y = y + 300;
// x = 0;
// }
}
}
void tic_tac_toe::showBoard()
{
}
void tic_tac_toe::buttonpressed()
{
button->setText("X");
}
I tried doing it with only one QPushbutton and it works, however when I move and create more buttons, the Slot function does not work on the buttons.
You only ever connect to the last QPushButton instance created. Move the connect call from the constructor into tic_tac_toe::initBoard and use a lambda to capture the value of button...
void tic_tac_toe::initBoard()
{
for (int i = 0; i < 10; i++) {
button = new QPushButton(this);
board.append(button);
button->show();
button->setFixedSize(300,300);
button->setText("??");
connect(button, &QPushButton::clicked, this,
[this, button]
{
buttonpressed(button);
});
}
}
Likewise, update the signature of tic_tac_toe::buttonpressed...
void tic_tac_toe::buttonpressed (QPushButton *button)
{
button->setText("X");
}
I have subclassed both a Qgraphicsscene and a Qgraphicsitem, it seems it works but trying to remove the items by subclass recognition don't works.
This delete the items:
void debugSceneItemscuatrobis()
{
QList<QGraphicsItem *> allitems = items();
foreach(auto item, allitems) {
removeItem(item);
}
}
But this doesn't, it recognizes there are items but doesn't remove them, tryed different posseibilities but couldn't make it works.
void debugSceneItemscuatrotris()
{
QList<QGraphicsItem *> allitems = items();
foreach(auto item, allitems) {
if(item->type() == chord::Type) {
removeItem(item);
delete item;
}
}
}
This is how the items were added by the qgraphicsitem subclass:
void chord::addchord(QPointF sp)
{
scene()->addLine(sp.x(), sp.y(), sp.x()+10, sp.y()+10);
QList<int> midics = {10, 30, 40};
for(int i = 0; i < midics.length(); i++)
{
QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem("n");
item->setFont(QFont("omheads", 20));
item->setPos(sp.x(), sp.y()+midics[i]);
scene()->addItem(item);
coso.append(item);
}
}
Sorry, I'm very newbie and no programmer, those are my first subclasses. Someone knows how it could be approached? Thanks. :-)
Without seeing more of your code I'm only guessing. But that guess would be that when you remove an item of type chord you are still able to see the various QGraphicsItems that were added to the scene in chord::addchord. If so it's probably due to the lack of any parent/child relationship between the chord and those items: from the documentation for QGraphicsScene::removeItem(item)...
Removes the item item and all its children from the scene.
Try creating the parent/child relationship explicitly by changing your chord:addchord implementation to...
void chord::addchord (QPointF sp)
{
auto *line = scene()->addLine(sp.x(), sp.y(), sp.x() + 10, sp.y() + 10);
line->setParentItem(this);
QList<int> midics = { 10, 30, 40 };
for (int i = 0; i < midics.length(); i++)
{
QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem("n", this);
item->setFont(QFont("omheads", 20));
item->setPos(sp.x(), sp.y() + midics[i]);
scene()->addItem(item);
coso.append(item);
}
}
It might not solve all of the issues but should (hopefully) head you in the right direction.
I make my own class from QWidget with redefine of paintEvent(), mousePressEvent(), mouseReleaseEvent() and mouseMoveEvent(). All that methods for move widgets over other widget (yellow).
When i create my widgets in a layout, it looks like this:
But when I move black widget to the bottom and red to the top like this:
and resize window, all widgets refresh to their align positions:
But i want, when i move one widget higher then another, the widgets should align in layout in new places, like this:
Which function i should redefine to do it?
P.S.
There is a piece of code, that can move widgets positions inside layout (change their indexes), but i don't know how find out their (x,y) position to calculate new indexes in layout. I think, that i can do it in resizeEvent().
But it when it event was emitted, positions already changed to old. (like before moveing on 1 picture), and i need positions after moveing (like on secon picture). How can i get position of widget before it will be aligned?
or How can i change order of widget in layout by drag and drop with the mouse?
I write my own widget, then redefine following methods: mouseReleaseEvent(), paintEvent(), mousePressEvent(), mouseMoveEvent(). In mousePressEvent() I hold old X and Y positions and mouse position on figure. Then in mouseMoveEvent() i calculate if minimum distance of mouse move is riched and move widget to new position (it not moves widget index in layout). After it, if emitted mouseReleaseEvent() i just calculate new index of moving widget and change and update parent layout. If widget moves less then it height, then layout just updates without changing widget index.
void SimpleWidget::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton))
return;
if (!IsMinimumDistanceRiched(event))
{
return;
}
int y = event->globalY() - mouseClickY + oldY;
int BottomBorder = parentWidget->geometry().height() - this->geometry().height();
if(y < 0) y = 0;
else if(y > BottomBorder) y = BottomBorder;
move(oldX, y);
}
void SimpleWidget::mousePressEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
dragStartPosition = event->pos();
oldX = this->geometry().x();
oldY = this->geometry().y();
mouseClickX = event->globalX();
mouseClickY = event->globalY();
}
bool SimpleWidget::IsMinimumDistanceRiched(QMouseEvent *event)
{
return (event->pos() - dragStartPosition).manhattanLength() >= QApplication::startDragDistance();
}
bool SimpleWidget::moveInLayout(QWidget *widget, MoveDirection direction)
{
QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(widget->parentWidget()->layout());
const int index = myLayout->indexOf(widget);
if (direction == MoveUp && index == 0)
{
return false;
}
if (direction == MoveDown && index == myLayout->count()-1 )
{
return false;
}
const int newIndex = direction == MoveUp ? index - 1 : index + 1;
myLayout->removeWidget(widget);
myLayout->insertWidget(newIndex , widget);
return true;
}
void SimpleWidget::paintEvent(QPaintEvent *)
{
QStyleOption o;
o.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
}
void SimpleWidget::mouseReleaseEvent(QMouseEvent *)
{
int y = geometry().y();
MoveDirection direct;
int offset;
if(oldY > y)
{
offset = oldY - y;
direct = MoveUp;
}
else if(oldY < y)
{
offset = y - oldY;
direct = MoveDown;
}
int count = offset/height();
for(int i = 0; i < count; i++)
{
moveInLayout(this, direct);
}
update();
QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(this->parentWidget->layout());
myLayout->update();
this->saveGeometry();
}
I have a hidden widget in my dialog. When I show it, I want the dialog window to expand accordingly and shrink again when I choose to hide it.
How can this be done? I have tried understanding the layout functionality of Qt but I find it very hard to grasp.
Try use QWidget::adjustSize() for container after show/hide content.
Not sure if there is a build-in solution, but this is my manual one:
Dialog::Dialog(QWidget *parent) :
QDialog(parent)
{
setupUi(this);
connect(toolButton, SIGNAL(toggled(bool)), SLOT(onToolButton(bool)));
onToolButton(false);
}
void Dialog::onToolButton(bool checked)
{
lineEdit->setVisible(checked);
int maxHeight = verticalLayout->contentsMargins().top()
+ verticalLayout->contentsMargins().bottom();
int itemsCount = 0;
for (int i = 0; i < verticalLayout->count(); ++i) {
QLayoutItem *item = verticalLayout->itemAt(i);
if (item->widget()) {
QWidget *w = item->widget();
if (w->isVisible()) {
maxHeight += w->geometry().height();
++itemsCount;
}
} else if (item->layout()) {
QLayout *l = item->layout();
maxHeight += l->geometry().height();
++itemsCount;
}
}
if (itemsCount > 1)
maxHeight += ((itemsCount - 1) * verticalLayout->spacing());
setMaximumHeight(maxHeight);
}
i need to use checkbox with text, like this "Check all":
in header of QStanndardItemModel. I tried like this
QStandardItem* item0 = new QStandardItem("some text");
item0->setCheckable(true);
item0->setCheckState(Qt::Checked);
item0->setText("some text");
_model->setHorizontalHeaderItem(1, item0);
This way only works for items not for header, i mean for items if i use
_model->setItem(new QStandardItem(some_item);
I heard about writing my own class which inherit QHeaderView but i dont know if this can help in my problem. I would ask if there is a easy way to achieve this?
Regards
i did something like this:
QStandardItemModel *model = new QStandardItemModel(this);
ui->tableView->setModel(model);
QtCheckHeaderView *header = new QtCheckHeaderView(Qt::Horizontal, ui->tableView);
QtCheckHeaderView *vheader = new QtCheckHeaderView(Qt::Vertical, ui->tableView);
ui->tableView->setHorizontalHeader(header);
ui->tableView->setVerticalHeader(vheader);
QStandardItem *root = model->invisibleRootItem();
QList<QList<QStandardItem *> > items;
for (int i = 0; i < 10; ++i)
{
QList<QStandardItem *> res;
for (int j = 0; j < 1000; ++j)
{
res.append(new QStandardItem(QString("%1;%2").arg(j).arg(i)));
vheader->addCheckable(j);
}
items.append(res);
root->appendColumn(res);
header->addCheckable(i);
}
this works great. Draws checkbox with text in vertical and horizontal header.
But this works great only if i put this code to MainWindow constructor. If i put this code to for example pushbutton function this wont work. Datas are fine but headers are invisible.
ui->tableView->repaint();
wont work. Someone maybe knows the answer why this is happening and/or how to solve this?
thanks for answer
Qt models don't support item flags for headers. Setting item flags on items that are used as headers has no effect. QHeaderView doesn't support drawing checkboxes. I'm afraid subclassing QHeaderView is the simpliest way.
I wrote an example of how it can be implemented based on this FAQ page. This class assumes that you use QStandardItemModel and uses flags of its header items. If someone would want to use other model class, subclassing QAbstractItemModel and implementing missing interface and changing headerview implementation would be needed.
class MyHeader : public QHeaderView
{
public:
MyHeader(Qt::Orientation orientation, QWidget * parent = 0);
protected:
QStandardItemModel* standard_model;
virtual void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const;
virtual void mousePressEvent(QMouseEvent *event);
virtual void setModel(QAbstractItemModel* model);
};
MyHeader::MyHeader(Qt::Orientation orientation, QWidget *parent) : QHeaderView(orientation, parent)
{
standard_model = 0;
}
void MyHeader::paintSection(QPainter *painter, const QRect &rect, int logical_index) const {
painter->save();
QHeaderView::paintSection(painter, rect, logical_index);
painter->restore();
if (standard_model && orientation() == Qt::Horizontal) {
QStandardItem* item = standard_model->horizontalHeaderItem(logical_index);
if (item && item->isCheckable()) {
int offset = (height() - style()->pixelMetric(QStyle::PM_IndicatorHeight))/2;
int pos = sectionViewportPosition(logical_index);
QStyleOptionButton option;
option.rect = QRect(offset + pos, offset,
style()->pixelMetric(QStyle::PM_IndicatorWidth),
style()->pixelMetric(QStyle::PM_IndicatorHeight));
if (item->checkState() == Qt::Checked) {
option.state = QStyle::State_On;
} else {
option.state = QStyle::State_Off;
}
option.state |= QStyle::State_Enabled;
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, &option, painter);
}
}
}
void MyHeader::mousePressEvent(QMouseEvent *event) {
int offset = (height() - style()->pixelMetric(QStyle::PM_IndicatorHeight))/2;
if (standard_model && orientation() == Qt::Horizontal) {
for(int logical_index = 0; logical_index < count(); logical_index++) {
int pos = sectionViewportPosition(logical_index);
QRect rect(offset + pos, offset,
style()->pixelMetric(QStyle::PM_IndicatorWidth),
style()->pixelMetric(QStyle::PM_IndicatorHeight));
if (rect.contains(event->pos())) {
QStandardItem* item = standard_model->horizontalHeaderItem(logical_index);
if (item && item->isCheckable()) {
item->setCheckState(item->checkState() == Qt::Checked ? Qt::Unchecked : Qt::Checked);
return;
}
}
}
}
QHeaderView::mousePressEvent(event);
}
void MyHeader::setModel(QAbstractItemModel *model) {
QHeaderView::setModel(model);
standard_model = qobject_cast<QStandardItemModel*>(model);
}
//usage
QTableView view;
QStandardItemModel model;
model.setColumnCount(5);
QStandardItem* item0 = new QStandardItem("some text");
item0->setCheckable(true);
item0->setCheckState(Qt::Checked);
item0->setText("some text");
model.setHorizontalHeaderItem(0, item0);
view.setModel(&model);
MyHeader *myHeader = new MyHeader(Qt::Horizontal, &view);
view.setHorizontalHeader(myHeader);
view.show();