PySide: Resizable scene in QGraphicsView - resize

I'm trying to find a way to mark the border of a QGraphicsScene, and make it resizable inside a QGraphicsView, to create something similar to Microsoft Paint.
In other words, my current QGraphicsView looks like this:
But my image is only this big, as indicated by the red box:
I want my QGraphicsView to be like this (the little black boxes are cornergrabbers for resizing the canvas):
Functionally, I want it to be similar to MS Paint:
The canvas (scene) is resizable, and the scrollbars on the window (view) appear when needed. The blue background color (solid gray background) appears behind the canvas.
How would I go about accomplishing this?
To try to get the grey background, I've been experimenting with QGraphicsView.setBackgroundBrush() and QGraphicsScene.setBackgroundBrush(). I've learned that QGraphicsView's background brush completely overrides QGraphicsScene's background brush if one is set. Even if I only set the background brush for QGraphicsScene, that background brush extends over the image's original boundaries.
Here is a link to my test code.
Help is appreciated!

I have to struggle with your constructors...dunno if it works on Windows, but have to make it to work with Linux. Try :
def setPixmap(self, pixmap):
if self.pixmap_item:
self.removeItem(self.pixmap_item)
self.pixmap_item = self.addPixmap(pixmap)
self.setPixBackGround()
def setPixBackGround(self):
# put Background rect for image
pixR = self.pixmap_item.pixmap().rect()
bgRectangle = self.addRect(pixR.x()-10, pixR.y()-10,
pixR.width()+20, pixR.height()+20)
# set color and Z value to put it behind image
bgColor = QColor(58, 176, 176)
bgRectangle.setBrush(bgColor)
bgRectangle.setZValue(-.1)
# take coordinates for brabbers
bgR = bgRectangle.rect()
grab1R = QRect(-5,-5,10,10)
# put grabbers as wish...
grab1 = self.addRect(grab1R)
grab1.setPos(bgR.topLeft())
grab2 = self.addRect(grab1R)
grab2.setPos(bgR.topRight())
# ....etc....

Related

Jetpack Compose OutlinedTextField with the label on the inside and golden glow around the outline when selected

I'm trying to make a TextField like in the image using Jetpack Compose.
So far no luck in finding a easy way.
The label must stay inside the outline, if I use OutlinedTextField there is no way to customise that. If I use the TextField which has the label on the inside there is no outline when selected, just the line below the textfield.
Also I need to add a shadow/glow effect with a custom color, here seen in gold.
I'm stumped..
Any thoughts?
You can do this by creating a Row with a Modifier.drawBehind that uses native paint to draw blur with color as in this image, the one with pink background has blur with same background color for shadow for instance, you can check the code for drawing colored blur here.
val myColor = color
.copy(alpha = shadow.alpha)
.toArgb()
val transparent = color
.copy(alpha = 0f)
.toArgb()
frameworkPaint.color = transparent
frameworkPaint.setShadowLayer(
radius,
dx,
dy,
myColor
)
it.drawRoundRect(
//...
paint = paint
)
It draws a shape behind you can draw a shape with stroke.
For the label and input create a Column with Modifier.weight() to use space inside row other than space reserved for Icon with close image.
Instead of TextField you can use a BasicTextfield which doesn't have default padding, however you can achieve the same thing with TextField too, but you will need to set colors to transparent to remove indicator line, it has some default padding you might not want to have.
TextField(
colors = TextFieldDefaults.textFieldColors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
)
)

How to save a scaled image inside QGRaphicsView using QFileDialog

I have a user interface with:
N.1 Push button (used to upload images)
N.2 QGraphicsView (left and right)
N.1 Push button that takes a print screen of the current image loaded on QGraphicsView left
Using the mouse is possible to:
1) zoom-in/zoom-out from the image
2) draw rectangles on the image.
I want to take the print screen of the image according to the zoom-in or zoom-out area I am using. However, once the file is saved it shows the entire image (wrong because I wanted only the enlarged or shrank part) with the rectangles drawn (this is correct).
According to this post QFileDialog was used in a similar way I am trying to do. I successfully used QFileDialog::getSaveFileName() to save the image. However it is not entirely solving the problem.
Below the pushbutton that takes care of taking the print screen of the image in the QGraphicsView left:
void MainWindow::on_addNewRecordBtn_clicked()
{
leftScene->clearSelection(); // Selections would also render to the file
leftScene->setSceneRect(leftScene->itemsBoundingRect()); // Re-shrink the scene to it's bounding contents
QImage image(leftScene->sceneRect().size().toSize(), QImage::Format_ARGB32); // Create the image with the exact size of the shrunk scene
image.fill(Qt::transparent); // Start all pixels transparent
QPainter painter(&image);
leftScene->render(&painter);
image.save(QFileDialog::getSaveFileName(this, tr("New Image Name"), QDir::rootPath(),
"Name (*.jpg *.jpeg *.png *.tiff *.tif)"));
}
The expected result would be saving the zoomed image (zoom.jpg for example) like this:
However when I save the image (zoom.jpg) the result that I am obtaining is constantly the entire image with the drawn features:
So if anyone needs, it is possible to take a print screen of an image no matter what the zoom in. Meaning you can zoom-in and zoom-out and take a print screen.
The following statement will do the job, grabbing the image your present (zoomed in or out status):
QImage image = ui->leftView->grab().toImage();
The only glitch is that the scroll bars horizontal and vertical (depending on the zoom) are also printed in your image. You can avoid that by setting them off right before taking the print screen and putting them back on right after.
Basically my previous function can be better written as follows:
void MainWindow::on_addNewRecordBtn_clicked()
{
leftScene->setSceneRect(leftScene->itemsBoundingRect());
// Setting off the scroll bars
ui->leftView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->leftView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QImage image = ui->leftView->grab().toImage();
image.save(QFileDialog::getSaveFileName(this, tr("New Image Name"), QDir::rootPath(),
"Name (*.jpg *.jpeg *.png *.tiff *.tif)"));
// Putting the scroll bars back on
ui->leftView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->leftView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
}
Hope this will be helpful in case you encountered my same problem.

How to smooth canvas drawing in Android?

I'm using Canvas for drawing in my Android application. But the result has bad quality (see the picture)
So, canvas drawing don't draw additional pixels with more dark color between "stairs pixels" for smoothing.
Like this
But I'm interesting how to do it.
Are there some preferences or methods for smoothing the picture? Thanx!
Edited: I've founded here
Use the ANTI-ALIAS flag for drawing smooth edges.
Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
//or
Paint p = new Paint();
p.setAntiAlias(true);

How to use mask with transparency on QWidget?

I am trying to use mask on my QWidget. I want to overlay existing widget with row of buttons - similar to Skype
Notice that these buttons don't have jagged edges - they are nicely antialiased and widget below them is still visible.
I tried to accomplish that using Qt Stylesheets but on pixels that should be "masked out" was just black colour - it was round button on black, rectangular background.
Then I tried to do this using QWidget::mask(). I used following code
QImage alpha_mask(QSize(50, 50), QImage::Format_ARGB32);
alpha_mask.fill(Qt::transparent);
QPainter painter(&alpha_mask);
painter.setBrush(Qt::black);
painter.setRenderHint(QPainter::Antialiasing);
painter.drawEllipse(QPoint(25,25), 24, 24);
QPixmap mask = QPixmap::fromImage(alpha_mask);
widget.setMask(mask.mask());
Sadly, it results in following effect
"Edges" are jagged, where they should be smooth. I saved generated mask so I could investigate if it was the problem
it wasn't.
I know that Linux version of Skype does use Qt so it should be possible to reproduce. But how?
One possible approach I see is the following.
Prepare a nice high resolution pixmap with the circular button icon over transparent background.
Paint the pixmap on a square widget.
Then mask the widget leaving just a little bit of margin beyond the border of the circular icon so that the widget mask jaggedness won't touch the smooth border of the icon.
I managed to get a nice circular button with not so much code.
Here is the constructor of my custom button:
Button::Button(Type t, QWidget *parent) : QPushButton(parent) {
setIcon(getIcon(t));
resize(30,30);
setMouseTracking(true);
// here I apply a centered mask and 2 pixels bigger than the button
setMask(QRegion(QRect(-1,-1,32,32),QRegion::Ellipse));
}
and in the style sheet I have the following:
Button {
border-radius: 15px;
background-color: rgb(136, 0, 170);
}
With border-radius I get the visual circle and the mask doesn't corrupt the edges because it is 1 pixel away.
You are using the wrong approach for generating masks. I would generate them from the button images themselves:
QImage image(widget.size(), QImage::Format_Alpha8);
widget.render(&image);
widget.setMask(QBitmap::fromImage(image.createMaskFromColor(qRgba(0, 0, 0, 0))));

How to set background color of an image using draw2d?

I have drawn one rectangle by using RectangleFigure in draw2d. And I am able to
color the rectangle figure by calling rectangleFigure.setBackgroundColor.
Now the same way I want to color the Image also. For that I used ImageFigure in
draw2d and I gave the background color by calling ImageFigure.setBackgroundColor().
But it does not give any color for me. So How can I give the background color
to the image figure in draw2d?
RectangleFigure extends Shape which draws it's own background by default. ImageFigure directly extends Figure which will only draw the background if you set it as Opaque:
imageFigure.setOpaque(true);