How do I create an image comparator in qt? - c++

I have two images--img1 and img2--and I would like to be able to compare both images. I would like to overlay them over each other with a slider which would let me see more of img1 or img2. Lastly, when I move in one image I would also like to move in the other img. This is what I have so far.
QGraphicsScene *scn = new QGraphicsScene( this );
ui->view->setScene( scn );
QPixmap *im = new QPixmap("P3C.jpg");
QPixmap *i = new QPixmap("result.jpg");
scn->addPixmap( *im );
scn->addPixmap(*i);

Use QGraphicsItemGroup to group the 2 pixmap items so they will act as one. Set the item group to ItemIsMovable so you can move them.
Set the opacity of the item that is on top of the other so the bottom one can show thru. You can connect the value change signal of your slider widget to your object's slot to control the opacity.

Related

How to determine current border color of QGroupBox?

I am using Qt 6.3 on Windows 11, and I am trying to figure out the current border color of QGroupBox in Fusion style.
I have subclassed QProxyStyle as my class GuiStyle, in my MainWindow constructor:
ui.setupUi(this);
auto guiStyle = new GuiStyle;
guiStyle->setBaseStyle(QStyleFactory::create("Fusion"));
qApp->setStyle(guiStyle);
qApp->setPalette(QPalette{QColor{0,0,0}});
My groupbox looks like this:
To figure out the current actual color of the border of QGroupBox I use QColorDialog and use the Pick Screen Color option then place my cursor exactly on top of the border of the QGroupBox. For different color of QPalette applied to QApplication I get different results:
qApp->setPalette(QPalette{QColor{0,0,0}}) => QColor(ARGB 1, 0.0901961, 0.0901961, 0.0901961)
qApp->setPalette(QPalette{QColor{10,10,10}}) => QColor(ARGB 1, 0.121569, 0.121569, 0.121569)
qApp->setPalette(QPalette{QColor{20,20,20}}) => QColor(ARGB 1, 0.152941, 0.152941, 0.152941)
Clearly, the border color of the QGroupBox is palette dependent. When I print out all colors of the current QPalette for each QPalette::ColorGroup and QPalette::ColorRole none of the color seems to match the current color which I get from the color picker of the QColorDialog. I tried to get all the values of the palette in the void GuiStyle::drawComplexControl function when the complex control is CC_GroupBox, in the void GuiStyle::drawPrimitive function when the primitive element is PE_Frame or PE_FrameGroupBox. But none of the colors seems to match the current border color of the QGroupBox. Is there any way I could determine this color programmatically?

Qt drawing a filled rounded rectangle with border

I want to draw a rectangle with rounded corners (border radius same for all 4 corners) with a specific color filling the entire rectangle, and a separate border color (say border is 1 px wide).
From my observation, Qt provides three methods - fillRect and drawRect and drawRoundedRect. I have tried them, they don't work like I want to. There is no method like fillRoundedRect. Which means that I can draw a rounded rectangle but it won't be filled with the color I want.
How do I do it? And also, I read that due to some aliasing problems, the corners are often rendered as unequal. How do I set it as equal for all four? Will painter.setRenderHint(QPainter::Antialiasing) suffice? Or do I have to do anything else?
You can create a QPainterPath, add the rounded rect to it, and then fill and stroke it:
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(QRectF(10, 10, 100, 50), 10, 10);
QPen pen(Qt::black, 10);
p.setPen(pen);
p.fillPath(path, Qt::red);
p.drawPath(path);
Note that even with antialiasing, 1 px border will probably never really look good, especially on a low DPI desktop monitor, on a high DPI mobile device it will be almost invisible.
If you create the rectangle as QRectF(9.5, 9.5, 100, 50) it will look better with 1 px antialiased border, because it will "snap" on the right pixel:
The answer above (from #dtech) works great, but can sometimes end up with an uneven border around the roundedRect. Using QPainter.strokePath() instead of QPainter.drawPath() can fix this issue.
Here is a python implementation of QPushButton, with paintEvent reimplemented:
# I use PySide6, but whatever library should work.
from PySide6.QtWidgets import QPushButton
from PySide6.QtGui import QPainter, QPainterPath, QBrush, QPen
from PySide6.QtCore import Qt, QRectF
class RoundedButton(QPushButton):
def __init__(self, text, bordersize, outlineColor, fillColor):
super(RoundedButton, self).__init__()
self.bordersize = bordersize
self.outlineColor = outlineColor
self.fillColor = fillColor
self.setText(text)
def paintEvent(self, event):
# Create the painter
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
# Create the path
path = QPainterPath()
# Set painter colors to given values.
pen = QPen(self.outlineColor, self.bordersize)
painter.setPen(pen)
brush = QBrush(self.fillColor)
painter.setBrush(brush)
rect = QRectF(event.rect())
# Slighly shrink dimensions to account for bordersize.
rect.adjust(self.bordersize/2, self.bordersize/2, -self.bordersize/2, -self.bordersize/2)
# Add the rect to path.
path.addRoundedRect(rect, 10, 10)
painter.setClipPath(path)
# Fill shape, draw the border and center the text.
painter.fillPath(path, painter.brush())
painter.strokePath(path, painter.pen())
painter.drawText(rect, Qt.AlignCenter, self.text())

QT gui items won't shrink to ft to their parent widget

I have three widgets under my main window . I design my program that each widget will be controlled by a class .
Last 2 hours I waste my time to fit 3 GUI elements to one of this widgets.
I want to have a label and a line item and a button. I put them in to a grid layout(in real case I have 3 row for simplicity I put 1 row in the example below). And set the grid layout's parent to my class.
What I expect is this GUI items to resize themselves and fit to one row in this widget, no matter what I tried I couldn't succeed .
In short I expect this items to shrink to fit to the widget by themselves. But couldn't figure out how to do it. Any advice ?
void
enviromentSetup::createDialogs()
{
numberOfPoints = new QLabel (QApplication::translate("leftPanel","numberOfPoints"));
inputNumberOfPoints = new
QLineEdit(QString::number(st_environmentParamaters.number_of_points_in_line));
maxElementsButton = new QPushButton("Max Elems");
gridLayout = new QGridLayout(this);
gridLayout->addWidget(numberOfPoints, 0, 0);
gridLayout->addWidget(inputNumberOfPoints, 0, 1);
gridLayout->addWidget(maxElementsButton, 0, 2);
this->show();
}
It is insufficient to merely make the parent of the layout the main widget. You also have to explicitly set the layout of the widget.
Add the following line just before you show the widget:
this->setLayout(gridLayout);

Huge "Grid" of PushButtons lags awfully, buttons can't be enabled

In my project, I have 256 tiny PushButtons in one 16x16 grid layout. (Yeah that took forever.) Editing and running my program now is very laggy. Also, for some strange reason, Qt will not let me enable any of the buttons, but other buttons to the side work just fine?
Is there any easy way to determine which square of the grid was clicked without having a bunch of buttons? (Like following the cursor over an image maybe?)
Also, when each "square" of the grid is clicked, it becomes the "selection" and it needs to be the only "square" selected. (Think about it like a huge chess board)
Here is a pic: http://gyazo.com/988cdbb59b3d1f1873c41bf91b1408fd
Later on, I will need to do this again for a 54x54 size grid (2916 buttons) and I REALLY don't want to do it button by button.
Thanks for your time, I hope you understand my question :)
You can do this easy way, I've explained almost everything in code, but if you have any questions about it feel free to ask, and please, accept this answer if it solved your problem :)
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import *
from PyQt4.QtCore import *
class DrawImage(QMainWindow):
def __init__(self, parent=None):
super(QMainWindow, self).__init__(parent)
self.setWindowTitle('Select Window')
#you can set grid size here ... 8x8, 16x16 , for bigger numbers (54x54) be sure your image is big enough, because QWidget can't be smaller then ~20 pixels
self.gridSize = 16
mainWidget = QWidget()
self.setCentralWidget(mainWidget)
self.scene = QGraphicsScene()
view = QGraphicsView(self.scene)
layout = QVBoxLayout()
layout.addWidget(view)
mainWidget.setLayout(layout)
self.image = QImage('image.JPG')# put your image name here, image (suppose to be grid) must be at the same folder or put full path
pixmapItem = QGraphicsPixmapItem(QPixmap(self.image), None, self.scene)
pixmapItem.mousePressEvent = self.pixelSelect
def pixelSelect( self, event ):
#add whatever you want to this widget,any functionality or you can add image for example, I've simply colored it
wdg = QWidget()
layout = QVBoxLayout()
palette = QPalette(wdg.palette())
palette.setBrush(QPalette.Background, QColor(200,255,255))
wdg.setPalette(palette)
wdg.setLayout(layout)
self.scene.addWidget(wdg)
#calculate size and position for added widget
imageSize = self.image.size()
width = imageSize.width()
height = imageSize.height()
#size
wgWidth = float(width)/self.gridSize
wgHeight = float(height)/self.gridSize
wdg.setFixedSize(wgWidth,wgHeight)
#position
wgXpos = int(event.pos().x()/wgWidth) * wgWidth
wgYpos = int(event.pos().y()/wgHeight) * wgHeight
wdg.move(wgXpos, wgYpos)
#which square is clicked?
print "square at row ", int(event.pos().y()/wgHeight)+1,", column ",int(event.pos().x()/wgWidth)+1, "is clicked"
def main():
app = QtGui.QApplication(sys.argv)
form = DrawImage()
form.show()
app.exec_()
if __name__ == '__main__':
main()
Also, if you want to display simple square image over your grid image, look at question/solution I had: QGraphicsPixmapItem won't show over the other QGraphicsPixmapItem
If you don't really need the appearance of buttons, I would create a QWidget subclass that implements a custom paintEvent and renders a grid of needed size (taking the widget size into account). Then, in the mouse events (up,down,move etc.) you can calculate which grid item was clicked with a simple formula. You can render cells with different colors to indicate selection or highlighting.
P.S.:I would really like to post some code from my implementations (i have done this two or three times) but the source codes are at my old company :)
You just create your own QGridLayout in order to be able to add the buttons easily.
I posted an answer to another question, showing you how to fill a custom made QGridLayout with a bunch of widgets sequentially. The buttons are added according to the maximum count of columns you specified. (Note: It's just a very rough example but enough to start from)
In your example you would create the custom grid layout with 16 columns and simply add your buttons.
To find out which button has been pressed (and to make connecting easier) you can use QSignalMapper.
For investigating the lag you could check the amount of (GDI-/User-) handles of your application (using ProcessExplorer for example). The handle count shouldn't be above 10.000.
I don't know why you can't enable the push buttons.

How to insert an image from file into a PlotWidget (plt1 = pg.PlotWidget(w);)?

How to insert an image from file into a PlotWidget (plt1 = pg.PlotWidget(w);)?
The image is for a layout on which some calculated and plotted points should appear.
I tried to insert the image in a Qlabel behind the PlotWidget and make the PlotWidget transparent, but didn't work as transparency takes the color of the window not real transparency.
Thanks
Use QGraphicsPixmapItem:
plt1 = pg.PlotWidget(w)
img = pg.QtGui.QGraphicsPixmapItem(pg.QtGui.QPixmap(fileName))
plt1.addItem(img)
# depending on your preference, you probably want to invert the image:
img.scale(1, -1)
# OR invert the entire view:
plt.invertY(True)