QGraphicsPixmapItem doesn't show in QGraphicsScene - qt

In the inherited class GraphicWidgetItem from QGraphicsItem, I create rectangles, a circle, and a picture. Everything is displayed except the picture. What am I doing wrong?
CustomItem::CustomItem( QObject *parent):
GraphicWidgetItem(parent)
{
QGraphicsRectItem *topLevel = new QGraphicsRectItem(this);
topLevel->setRect(0, 0, 20, 20);
topLevel->setBrush(Qt::gray);
topLevel->setPos(-30 , -30);
QGraphicsRectItem *lowLevel = new QGraphicsRectItem(this);
lowLevel->setRect(0, 0, 20, 20);
lowLevel->setBrush(Qt::red);
lowLevel->setPos(-30 , 60);
QGraphicsEllipseItem *circle = new QGraphicsEllipseItem(this);
circle->setBrush(Qt::green);
circle->setRect(0, 0, 20, 20);
QGraphicsPixmapItem* pi = new QGraphicsPixmapItem(QPixmap(":/icons/image"));
}

There is only 2 way for an item to appear in the scene:
Add directly using addItem().
Or be the children of an item that is already on the scene.
In your case "rectangles" and "circles" are shown because they are children of CustomItem but "pi" is not so it fails, the solution is to pass to "this" as parent:
QGraphicsPixmapItem* pi = new QGraphicsPixmapItem(QPixmap(":/icons/image"), this);
Or
QGraphicsPixmapItem* pi = new QGraphicsPixmapItem(QPixmap(":/icons/image"));
pi->setParent(this);

Related

How to bind TextField and ProgressBar in JavaFx

I'm trying to Use reactive bindings to bind the value of alcoholPercentageField to the progress property of alcoholBar.
The progress bar will "full" when alcoholic content is set to 20 % and empty when the alcoholic content is 0
My Code-
public void start(Stage stage) throws Exception {
stage.setTitle("Mead calculator");
// Creating the fields and components
TextField waterAmountField = new TextField();
TextField alcoholPercentageField = new TextField();
TextField sugarAmountField = new TextField();
Label meadTotalAmount = new Label();
Label assessmentLabel = new Label("");
//assessmentLabel.textProperty().bind(alcoholPercentageField.textProperty());
//Conditional Binding Error
assessmentLabel.textProperty().bind(Bindings.when((alcoholPercentageField.textProperty().lessThan(5))).then("Smart").otherwise("Bad"));
ProgressBar alcoholBar = new ProgressBar();
//Error is here
alcoholBar.progressProperty().bind(alcoholPercentageField.textProperty() * 5);
Rest of the Code: some visual things
GridPane grid = new GridPane();
grid.setAlignment(Pos.CENTER);
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 25, 25, 25));
var columnOneConstraints = new ColumnConstraints(150, 150, Double.MAX_VALUE);
columnOneConstraints.setHalignment(HPos.RIGHT);
var columnTwoConstrains = new ColumnConstraints(200,200, Double.MAX_VALUE);
columnTwoConstrains.setHgrow(Priority.SOMETIMES);
grid.getColumnConstraints().addAll(columnOneConstraints, columnTwoConstrains);
alcoholBar.setMaxWidth(Double.MAX_VALUE);
GridPane.setColumnSpan(alcoholBar, 2);
GridPane.setHalignment(assessmentLabel, HPos.RIGHT);
sugarAmountField.setDisable(true);
grid.add(new Label("Water (l):"), 0, 0);
grid.add(waterAmountField, 1, 0);
grid.add(new Label("Vol-%:"), 0, 1);
grid.add(alcoholPercentageField, 1, 1);
grid.add(new Label("Sugar (kg):"), 0, 2);
grid.add(sugarAmountField, 1, 2);
grid.add(new Label("Lemons: "), 0, 3);
grid.add(new Label("To taste"), 1, 3);
grid.add(new Label("Mead total (kg):"), 0, 4);
grid.add(meadTotalAmount, 1, 4);
grid.add(alcoholBar, 0, 5);
grid.add(assessmentLabel, 1, 6);
// Okay, layout creation stops here
// And of course set the scene and show the stage as always
stage.setScene(new Scene(grid, 500, 400));
stage.show();
}
}
You need to create some additional Property and Binding objects.
First, create properties for your TextField alcoholPercentageField. Then, you'll bind them using a StringConverter to convert the text entered into doubles.
Finally, use bindBidirectional to propagate and lastly bind it with progressBar by dividing 20 ( The progress bar will be "full" when alcoholic content is set to 20 %)
Code Will be like this-
// Properties used for bindings
DoubleProperty alcoholPercent = new SimpleDoubleProperty();
//Setup the converters to get the input from the textfields
StringConverter<? extends Number> converter = new DoubleStringConverter();
Bindings.bindBidirectional(alcoholPercentageField.textProperty(), alcoholPercent, (StringConverter<Number>) converter);
alcoholBar.progressProperty().bind(alcoholPercent.divide(20));
For Conditional Binding, check this Conditional Binding
Code would be like this-
assessmentLabel.textProperty().bind(Bindings.when(alcoholPercent.lessThan(5)).then("Smart").otherwise("Bad"));
assessmentLabel.textFillProperty().bind(Bindings.when(alcoholPercent.lessThan(5)).then(Color.GREEN).otherwise(Color.RED));
Use the Bindings API.
Note that the progress is supposed to be between 0 and 1, so if you are entering percentages, instead of proportions, into your text field you need to divide by 100:
alcoholBar.progressProperty().bind(Bindings.createDoubleBinding(
() -> 0.05 * Double.parseDouble(alcoholPercentageField.getText()),
alcoholPercentageField.textProperty()
));
You might want to implement more complex logic to, e.g. check for a valid number, or at least non-empty text field.

qcustomplot: set item by name and find them

I have used the qcustomplot to draw item.
I have two item.
One is item text, another is item rect.
What I want to do is when I select the text, the item rect change the color.
I have used the itemAt to check whether the mouse has clicked a item.
But I have encountered two problems
I don't know what item text I selected.
I don't know how to find the specific item rect by name.
Code:
//item text
QCPItemText *text= new QCPItemText(ui->customPlot);
ui->customPlot->addItem(text);
text->setSelectable(true);
text->position->setCoords(10, 30);
text->setText("text");
text->setFont(QFont(font().family(), 9));
// item rect
QCPItemRect *rect= new QCPItemRect(ui->customPlot);
ui->customPlot->addItem(rect);
rect->setPen(QPen(QColor(50, 0, 0, 100)));
rect->setSelectedPen(QPen(QColor(0, 255, 0, 100)));
rect->setBrush(QBrush(QColor(50, 0, 0, 100)));
rect->setSelectedBrush(QBrush(QColor(0, 255, 0, 100)));
rect->topLeft->setCoords(0,10);
rect->bottomRight->setCoords(10,0);
connect(ui->customPlot, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(moveOver(QMouseEvent*)));
moveOver(QMouseEvent* event)
{
QPoint pos = event->pos();
QCPAbstractItem *item = ui->customPlot->itemAt(pos, true);
if(item != 0) qDebug() << "moved over";
}
First, in order to change rect color inside your moveOver event you can save it as a data member of the class.
Second, because both QCPItemRect and QCPItemText inherits from QCPAbstractItem you can use dynamic_cast. You can try to cast it to QCPItemText and if the cast will fail your pointer will be null. Take a look also at this post.
So, your code should look like:
moveOver(QMouseEvent* event)
{
QPoint pos = event->pos();
QCPAbstractItem *item = ui->customPlot->itemAt(pos, true);
textItem = QCPItemText* dynamic_cast<QCPItemText*> (item);
if (textItem == 0){
//item is not a QCPItemText
**do something**
}
else{
//item is a QCPItemText - change rect color
rect->setBrush(QBrush(QColor(50, 0, 0, 100)));
}
}

Displaying two widgets in MainWindow

I am new to Qt. As it stands, I have a table with a button btn. When the button is clicked the setCentralWidget(view) takes over the window so I can no longer see the table obviously. But if I remove the setCentralWidget(view), nothing displays when I click the button.
Is there a way I can display both in the same window? Split or dock maybe?
(I have removed code that is irrelevant to my question)
MainWindow::MainWindow()
{
//etc
packet = new QTabWidget;
setCentralWidget(packet)
}
//other code
void MainWindow::create(const QString &a)
{
QTableWidget* table = new QTableWidget;
int tabIndex = packet->addTab(table, a);
packet->setCurrentIndex(tabIndex);
table->setRowCount(1);
table->setColumnCount(2);
table->setHorizontalHeaderLabels(QString("a;Simulator").split(";"));"));
table->setItem(0,0,new QTableWidgetItem(a));
QPushButton *btn = new QPushButton("load", this);
connect(btn, SIGNAL(clicked()), this, SLOT(sim()));
table->setCellWidget(0,1, btn);
}
void MainWindow::sim()
{
QGraphicsScene* scene = new QGraphicsScene(QRect(-10, -10, 100, 50));
QGraphicsView* view = new QGraphicsView();
scene->addText("Network");
view->setScene(scene);
view->setGeometry(QRect(10, 10, 100, 50));
setCentralWidget(view);
}
You should look at the QMdiArea class - it's designed to be used as the central widget of a Main Window that can have many inner widgets. It has a variety of layout styles as well - scroll down on that page to see the examples.
Hope that helps!
You should subclass QWidget. For example make your own MyWidget class. And this class will include a QGraphicsView and a QTabWidget in a splitter for example. And in your MainWindow set the central widget as an instance of MyWidget.

QGraphicScene Pop Ups for a second then vanishes

I have a all my code inside the constructor of a mainWindow. The problem is that the display only pop ups for a second and than vanishes. Any help will be much appreciated . Following is the code.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QPixmap kineticPix(":/images/kinetic.png");
QPixmap bgPix(":/images/Time-For-Lunch-2.jpg");
QGraphicsScene scene(-350, -350, 700, 700);
QGraphicsItem *buttonParent = new QGraphicsRectItem;
Button *ellipseButton = new Button(QPixmap(":/images/ellipse.png"), buttonParent);
Button *figure8Button = new Button(QPixmap(":/images/figure8.png"), buttonParent);
Button *randomButton = new Button(QPixmap(":/images/random.png"), buttonParent);
Button *tiledButton = new Button(QPixmap(":/images/tile.png"), buttonParent);
Button *centeredButton = new Button(QPixmap(":/images/centered.png"), buttonParent);
ellipseButton->setPos(-100, -100);
figure8Button->setPos(100, -100);
randomButton->setPos(0, 0);
tiledButton->setPos(-100, 100);
centeredButton->setPos(100, 100);
scene.addItem(buttonParent);
buttonParent->scale(0.75, 0.75);
buttonParent->setPos(200, 200);
buttonParent->setZValue(65);
}
You have created the scene on the stack and not assigned it to a member variable, so as soon as control leaves the constructor it is deleted.

QWidget::setLayout error : Attempting to set QLayout [...], which already has a layout

On execution (no compile error) I get on the console
QWidget::setLayout: Attempting to set QLayout "" on CGSearchResult "",
which already has a layout
I am using the following code:
CGSearchResult::CGSearchResult(QWidget *parent) : QWidget(parent)
{
initControls();
SetTableContent();
}
void CGSearchResult::initControls()
{
backButton = new QPushButton(tr("&Back"));
connect(backButton, SIGNAL(clicked()), this, SLOT(showHome()));
model=new QStandardItemModel();
QWidget::setFont(QFont("Courier New", 8, QFont::Bold));
searchTable = new QTableView(this);
searchTable->showGrid();
searchTable->resize(720,400);
searchTable->horizontalHeader()->setDefaultSectionSize(170);
searchTable->verticalHeader()->setDefaultSectionSize(50);
searchTable->verticalHeader()->hide();
searchTable->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
searchTable->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QGridLayout *layout = new QGridLayout();
layout->addWidget(backButton, 0, 0, 1, 1);
layout->addWidget(searchTable, 2, 0, 1, 1);
setLayout(layout);
}
http://qt-project.org/doc/qt-4.8/qwidget.html#setLayout
If there already is a layout manager installed on this widget, QWidget won't let you install another. You must first delete the existing layout manager (returned by layout()) before you can call setLayout() with the new layout.

Resources