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)));
}
}
Related
GridPane layout = new GridPane();
Label wordInstruction = new Label("Word");
TextField wordField = new TextField();
Label translationInstruction = new Label("Translation");
TextField translationField = new TextField();
Label error = new Label();
layout.setVgap(10);
layout.setHgap(10);
layout.setPadding(new Insets(10, 10, 10, 10));
layout.setAlignment(Pos.CENTER);
Button addButton = new Button("Add");
// Stops the button from consuming mouse events and allows it to become the default button.
addButton.setSkin(new ButtonSkin(addButton) {
{
this.consumeMouseEvents(false);
}
});
// The button can now be pressed with the enter key.
addButton.setDefaultButton(true);
layout.add(wordInstruction, 0, 0);
layout.add(wordField, 0, 1);
layout.add(translationInstruction, 0, 2);
layout.add(translationField, 0, 3);
layout.add(addButton, 0, 4);
layout.add(error, 0, 6);
addButton.setOnAction((event) -> {
String word = wordField.getText();
String translation = translationField.getText();
if (!translationField.getText().isEmpty()) {
this.dictionary.add(word.toLowerCase(), translation.toLowerCase());
error.setText("");
wordField.clear();
} else {
error.setText("Please input a translation.");
}
translationField.clear();
});
return layout;
}
Hello, I've just started using JavaFX and I've not been able to find anything in the documentation related to my problem. When I press the addButton, I want the user to be able to write into the wordField textField straight away instead of having to click it or tab all the way to it. Is there any way to make the textField active in my addButton.setOnAction function?
Thank you in advance.
How about running the TextField.requestFocus() method?
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);
I have two controls in my JavaFx Application
1. TextField
2. ListView
I want to place ListView just below the TextField using co-ordinates of TextField.
Because position of TextField changes.
Details :
I am creating auto suggestion text field for my project which requires to pop up a list when users type something in text field. that text field may exist anywhere in the scene it can be in another list view also. So what I need precisely is how to obtain co-ordinates of text field on screen so that I can place list view just below the text field.
I see multiple options here:
I think you might be better of using a ContextMenu. When you show a ContextMenu you can define a view that it should be shown relative to and a side of the view to show it.
Should a ContextMenu not fulfill your demands, the easiest idea that I have is that you replace your TextField with a VBox and input the TextField and the ListView in the VBox. That will make them be together and you can just position the VBox like you would position your TextField.
Last if you want to lay it out yourself, the TextField contains Properties like layoutX and layoutY and height and width. Using those you can calculate where to position your ListView (e.g. Y position of ListView would be textField.layoutY + textField.height). To keep this position up to date I see two options:
To position the TextField you have probably overwritten the layoutChildrens method of some Parent, so you can probably put this code there.
If not, you can also register ChangeListeners on those Properties to get notified when they change and reposition your ListView accordingly.
To get the location of a text field in the screen coordinates, you can do
Bounds boundsInScreen = textField.localToScreen(textField.getBoundsInLocal());
This returns a Bounds object, from which you can get the various coordinates, e.g.
Popup popup = ... ;
popup.setWidth(boundsInScreen.getWidth());
popup.show(textField, boundsInScreen.getMinX(), boundsInScreen.getMaxY());
I Created this helper class that does just that.
public class PositionUtils {
public static void position(Region movable, Region reference, Anchor movableAnchor, Anchor referenceAnchor, float xOffset, float yOffset) {
double x = reference.localToScene(reference.getBoundsInLocal()).getMaxX();
double y = reference.localToScene(reference.getBoundsInLocal()).getMaxY();
Point referencePoint = referenceAnchor.referencePoint;
Point movablePoint = movableAnchor.movablePoint;
x -= (0.5 * movable.getWidth()) * movablePoint.x;
y += (0.5 * movable.getHeight()) * movablePoint.y;
x += (0.5 * reference.getWidth()) * referencePoint.x;
y -= (0.5 * reference.getHeight()) * referencePoint.y;
movable.setLayoutX(x + xOffset);
movable.setLayoutY(y + yOffset);
}
public static void position(Pane movable, Pane reference, Anchor movableAnchor, Anchor referenceAnchor) {
position(movable, reference, movableAnchor, referenceAnchor, 0, 0);
}
public static void position(Pane movable, Pane reference, Side side) {
position(movable, reference, side, 0, 0);
}
public static void position(Pane movable, Pane reference, Side side, float xOffset, float yOffset) {
Anchor movableAnchor = null;
Anchor referenceAnchor = null;
switch (side) {
case TOP:
movableAnchor = Anchor.BOTTOM_CENTER;
referenceAnchor = Anchor.TOP_CENTER;
break;
case BOTTOM:
movableAnchor = Anchor.TOP_CENTER;
referenceAnchor = Anchor.BOTTOM_CENTER;
break;
case RIGHT:
movableAnchor = Anchor.CENTER_LEFT;
referenceAnchor = Anchor.CENTER_RIGHT;
break;
case LEFT:
movableAnchor = Anchor.CENTER_RIGHT;
referenceAnchor = Anchor.CENTER_LEFT;
break;
}
position(movable, reference, movableAnchor, referenceAnchor, xOffset, yOffset);
}
public enum Anchor {
TOP_LEFT(new Point(0, 0), new Point(-2, 2)),
TOP_CENTER(new Point(1, 0), new Point(-1, 2)),
TOP_RIGHT(new Point(2, 0), new Point(0, 2)),
CENTER_LEFT(new Point(0, -1), new Point(-2, 1)),
CENTER(new Point(1, -1), new Point(-1, 1)),
CENTER_RIGHT(new Point(1, -2), new Point(0, 1)),
BOTTOM_LEFT(new Point(0, -2), new Point(-2, 0)),
BOTTOM_CENTER(new Point(1, -2), new Point(-1, 0)),
BOTTOM_RIGHT(new Point(2, -2), new Point(0, 0));
public Point referencePoint;
public Point movablePoint;
Anchor(Point movablePoint, Point referencePoint) {
this.referencePoint = referencePoint;
this.movablePoint = movablePoint;
}
}
public enum Side {
TOP,
BOTTOM,
RIGHT,
LEFT
}
}
I want to dynamically create X labels on a layout. The X is taken from the QSpinBox.
When X is decreased, I need to first remove items on layout and then create a new one, with decreased number of labels:
void dial::quantity1SpinClicked(int val)
{
QLayout *layout = fqbox->layout();
if(layout != 0)
{
QLayoutItem *item;
while ((item = layout->takeAt(0)) != 0)
layout->removeItem (item);
delete layout;
}
QGridLayout *gridLayout = new QGridLayout;
QList<QLabel*> labels;
for (int i = 0; i < val; ++i){
labels << new QLabel(QObject::tr("nr %1").arg(i));
gridLayout->addWidget(labels.at(i), i, 0);
}
fqbox->setLayout(gridLayout);
}
However, my code does not remove items, it creates a new layout, on top on the old one (it looks like so):
How to solve this?
It is needed to delete QLabel widget:
QLayoutItem *item;
while ((item = layout->takeAt(0)) != 0) {
layout->removeItem (item);
delete item->widget();
delete item;
}
Note also description of QLayout::removeItem(QLayoutItem * item):
It is the caller's responsibility to delete the item.
Notice that item can be a layout (since QLayout inherits
QLayoutItem).
I have a grid with few columns with its borders custom drawn. But when we compare the borders of the custom drawn with the normal(non customised) columns it is like little thicker. So if we apply back color, will fill the whole cell like in Row number 2, Column 1. Is there any way to remove this thickness so that customised and non customised cells should look similar.
Blockquote
The code is as follows:
private void uxGrid_CustomDrawCell(object sender, RowcellCustomDrawEventArgs e)
{
if(col==1)
{
DrawCellBorder(b,e.bounds);
}
}
private void DrawCellBorder(RowCellCustomDrawEventArgs e, int top, int left, int right, int bottom)
{
Brush b = Brushes.Red;
if(top ==1)
e.Graphics.Fillrectangle(b, new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bound.Width,1));
if(right ==1)
e.Graphics.Fillrectangle(b, new Rectangle(e.Bounds.X.Right, e.Bounds.Y, 1, e.Bound.Height));
if(bottom ==1)
e.Graphics.Fillrectangle(b, new Rectangle(e.Bounds.X, e.Bounds.Bottom, e.Bound.Width,1));
if(left ==1)
e.Graphics.Fillrectangle(b, new Rectangle(e.Bounds.X, e.Bounds.Y, 1, e.Bounds.Height));
}
I beieve you can use the following code:
void gridView1_CustomDrawCell(object sender, RowCellCustomDrawEventArgs e) {
var cellBounds = ((DevExpress.XtraGrid.Views.Grid.ViewInfo.GridCellInfo)e.Cell).Bounds;
DrawCellBorder(e.Graphics, Brushes.Red, cellBounds, 1);
}
void DrawCellBorder(Graphics g, Brush borderBrush, Rectangle cellBounds, int borderThickness) {
Rectangle innerRect = Rectangle.Inflate(cellBounds, -borderThickness,- borderThickness);
g.ExcludeClip(innerRect);
g.FillRectangle(borderBrush, cellBounds);
}
Note that e.Bounds returns a cell content rectangle within the CustomDrawCell event handler (not the entire cell bounds).
I've done it with this code, hope it helps: (Works for Totals)
`if (e.RowValueType == PivotGridValueType.Total)
{
e.GraphicsCache.FillRectangle(new LinearGradientBrush(e.Bounds, Color.LightBlue, Color.Blue, LinearGradientMode.Vertical), e.Bounds);
Rectangle innerRect = Rectangle.Inflate(e.Bounds, -3, -3);
e.GraphicsCache.FillRectangle(new LinearGradientBrush(e.Bounds, Color.Blue,
Color.LightSkyBlue, LinearGradientMode.Vertical), innerRect);
e.GraphicsCache.DrawString(e.DisplayText, e.Appearance.Font,
new SolidBrush(Color.White), innerRect, e.Appearance.GetStringFormat());
e.Handled = true;
} '