Scaling GraphicsView Widget With Sliders While displaying a Pixmap - qt

I am trying to use the scale(qreal x, qreal y) method/function for Graphics view to scale a pixmap in the graphics view widget. Below I've attached code of my attempts. When I execute the program it will display my pixmap but as soon as I move the horizontal slider the pixmap disappears and the graphics view just displays a blank white page. The commented out parts are all things I have tried but produced the same result. I'm not entirely sure if scaling the graphics view will scale everything in the graphics view, I assumed so but could not find anything concrete from the documentation.
*One thing to note is that I have a button that displays two different Pixmaps, even after I am presented with the white screen upon moving the scroll bar, if I press the button it will still update the y axis scroll bar(as one pixmap is slightly larger than the graphics widget) however a blank white graphics view is still displayed
*PixMapView is the name of the graphics view widget
void CanvasTest::on_horizontalSlider_valueChanged(int value)
{
//int scaleX = value/(ui->horizontalSlider->maximum())*2;
//Graph is updating and Y scroll bar is updating to show for it
//int scaleY = ui->verticalSlider->value();
QGraphicsScene* scene = ui->PixMapView->scene();
ui->PixMapView->scale(value/10, 1);
ui->PixMapView->setScene(scene);
ui->PixMapView->show();
}

There was truncation issue using integers, this code also uses static variables to keep track of the previous scale values.
static float valueTracker = 1;\
static float valueTracker1 = 1;
static int count = 1;
bool order;
if (count%2 == 1)
{
valueTracker = newSliderValue;
order = 0;
}
else
{
valueTracker1 = newSliderValue;
order = 1;
}
if(valueTracker == valueTracker1 || valueTracker == 0 || valueTracker1 == 0)
{
count++;
return;
}
else if(order == 0)
{
ui->PixMapView->scale(((valueTracker/valueTracker1)), 1);
}
else if(order == 1)
{
ui->PixMapView->scale(((valueTracker1/valueTracker)), 1);
}
count++;

Related

QT overlapping camera windows issue

We have an overlapping issue on QT Widget windows. 3 camera windows are displayed in our main application. When we zoomed in one of the window, it displays full screen view. However, after approx. 10 minutes, we see other two camera windows on top of zoomed in window (overlapping).
Attaching the screen shot for visualization.
Below is the code snippet for zoom-in and zoom-out functionality.
overlapping camera output
//For making invisible background windows that were coming after zoom in
void MyCamera::zoomInCamera(uint cameraHandle, int camearachanelid)
{
//Start - For continuous clicking
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
GstreamerStream *camHandle=NULL;
if(CAMERA_HANDLE_VALID == isHandleValid(cameraHandle))
{
camHandle = (GstreamerStream*)cameraHandle;
camHandle->zoomInCameraThread();
QWidget *window = camHandle->getWindowObj();
window->setWindowState(window->windowState() ^ Qt::WindowActive);
}
for(int i=0;i<3;i++){
GstreamerStream *camHandleVar = (GstreamerStream*)m_CameraHandles[i];
if( cameraHandle != m_CameraHandles[i] ){
QWidget *window = camHandleVar->getWindowObj();
window->setUpdatesEnabled(false);
//window->hide();
}
}
QApplication::restoreOverrideCursor();
}
//Start - For showing invisible windows after zoom out
void MyCamera::zoomOutCamera(uint cameraHandle, int camearachanelid)
{
//Start - By - For continuous clicking
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
GstreamerStream *camHandle=NULL;
if(CAMERA_HANDLE_VALID == isHandleValid(cameraHandle))
{
camHandle = (GstreamerStream*)cameraHandle;
camHandle->zoomOutCameraThread();
QWidget *window = camHandle->getWindowObj();
window->setWindowState(window->windowState() ^ Qt::WindowActive);
}
for(int i=0;i<3;i++){
GstreamerStream *camHandleVar = (GstreamerStream*)m_CameraHandles[i];
if( cameraHandle != m_CameraHandles[i] ){
QWidget *window = camHandleVar->getWindowObj();
//Added below line
window->setUpdatesEnabled(true);
window->setWindowState(window->windowState() ^ Qt::WindowActive);
}
}
QApplication::restoreOverrideCursor();
}
==========================================================
I tried using setWindowState, setUpdatesEnabled API calls, but it is not working as per expected behaviour.
How do I prevent the windows overlapping issue?
Regards
Amar

How to scale the contents of a QGraphicsView using the QPinchGesture?

I'm implementing an image viewer on an embedded platform. The hardware is a sort of tablet and has a touch screen as input device. The Qt version I'm using is 5.4.3.
The QGraphicsView is used to display a QGraphicsScene which contains a QGraphicsPixmapItem. The QGraphicsPixmapItem containts the pixmap to display.
The relevant part of the code is the following:
void MyGraphicsView::pinchTriggered(QPinchGesture *gesture)
{
QPinchGesture::ChangeFlags changeFlags = gesture->changeFlags();
if (changeFlags & QPinchGesture::ScaleFactorChanged) {
currentStepScaleFactor = gesture->totalScaleFactor();
}
if (gesture->state() == Qt::GestureFinished) {
scaleFactor *= currentStepScaleFactor;
currentStepScaleFactor = 1;
return;
}
// Compute the scale factor based on the current pinch level
qreal sxy = scaleFactor * currentStepScaleFactor;
// Get the pointer to the currently displayed picture
QList<QGraphicsItem *> listOfItems = items();
QGraphicsItem* item = listOfItems.at(0);
// Scale the picture
item.setScale(sxy);
// Adapt the scene to the scaled picture
setSceneRect(scene()->itemsBoundingRect());
}
As result of the pinch, the pixmap is scaled starting from the top-left corner of the view.
How to scale the pixmap respect to the center of the QPinchGesture?
From The Docs
The item is scaled around its transform origin point, which by default is (0, 0). You can select a different transformation origin by calling setTransformOriginPoint().
That function takes in a QPoint so you would need to find out your centre point first then set the origin point.
void QGraphicsItem::setTransformOriginPoint(const QPointF & origin)

How do I clear certain lines/paths from a QWidget but not others, then redraw separate lines/paths on top?

I'm trying to optimize line drawings on a QWidget. I basically have a grid in the background and drawings on top of the grid. Currently I'm redrawing the background and grid lines every time the paint event is called. This works fine if the grid lines are far enough apart so I don't have to draw that many lines, but if the scale gets changed, the lines must be redrawn at that new scale. Also, if the window is resized, then more of the grid is displayed, hurting the performance even more.
Here is the code for drawing the grid:
// draw grid
painter.fillRect(0,0,areaWidth, areaHeight, QColor(255,255,255));
painter.setPen(QPen(QBrush(QColor(240,240,255)), 1, Qt::SolidLine, Qt::FlatCap));
int numXLines = areaWidth/mSIToPixelScale + 1;
int numYLines = areaHeight/mSIToPixelScale + 1;
double width = areaWidth;
double height = areaHeight;
for (int x=0; x<numXLines;x++)
{
for (int y=0; y<numYLines; y++)
{
painter.drawLine(0,y*mSIToPixelScale,width, y*mSIToPixelScale);
painter.drawLine(x*mSIToPixelScale,0,x*mSIToPixelScale,height);
}
}
So when numXLines and numYLines in the above code reach higher values, the performance drops very hard, which makes sense. The grid will always have to be redrawn if the scale changes, but if the scale does not change, then only the drawing on top of the grid should change. How can I accomplish this?
The QWidget::paintEvent( QPaintEvent* aEvent ) is called by the framework not just when you want it. So if you want to remove some lines from the widget than you need draw them conditionally in your function.
For example:
if ( numXLines < 25 && numYLines < 25 )
{
// Draw only every second lines for example.
}
else
{
// Draw all lines.
}
But this is not the best way. Maybe you shall use larger steps between the grid lines if there too many of them.
I found where I went wrong, I was redrawing the y lines every x iteration. I fixed it by creating two separate for loops:
// add grid lines to a painter path
QPainterPath grid;
for (int x=0; x<numXLines;x++)
{
grid.moveTo(x*mSIToPixelScale, 0);
grid.lineTo(x*mSIToPixelScale, height);
}
for (int y=0; y<numYLines; y++)
{
grid.moveTo(0, y*mSIToPixelScale);
grid.lineTo(width,y*mSIToPixelScale);
}
painter.drawPath(grid);
painter.end();
Also, I think drawing onto a QImage first then drawing that image inside the paintEvent would make code more organized, so all your doing in the paintEvent is drawing from a high level.

Displaying image as background of QGraphicsScene

I try to use QGraphicsView to display a map with some QGraphicItem-subclass showing region centers of the map. Conceptually, I organize the map as follow:
QGraphicsView
QGraphicsScene
QGraphicsPixmapItem : background image, fixed until next call of loadSetting
QGraphicsRectItem : legend, position relative to bg is fixed throughout app
QGraphicsEllipseItem : region centers
I want the map to behave as follow:
no scrollbars to be displayed, and the background image fillup all the visible area of the view/scene.
when the widget is re-sized, the QGraphics*Items will re-size themselves accordingly (as if the view is zoomed)
relative positions of QGraphicsEllipseItems, remain fixed until next call of loadSetting()
Now I have problem in getting the background image displayed properly.
Constructor [I'm adding this view to a QTabWidget directly: myTab->addTab("name", my_view_); ]
MyView::MyView(QWidget *parent) : QGraphicsView(parent) {
bg_pixmap_ = new QGraphicsPixmapItem();
legend_ = new MapLegend();
setScene(new QGraphicsScene(this));
scene()->addItem(bg_pixmap_);
scene()->addItem(legend_);
}
Load map setting (during program execution, this method may be invoked multiple times)
void MyView::loadSetting(Config* cfg) {
if (!cfg) return;
/* (a) */
scene()->clearFocus();
scene()->clearSelection();
for (int i = 0; i < symbols_.size(); i++)
scene()->removeItem(symbols_[i]);
qDeleteAll(symbols_);
symbols_.clear();
/* (a) */
/* (b) */
background_ = QPixmap(QString::fromStdString(cfg->district_map));
bg_pixmap_->setPixmap(background_);
for (size_t i = 0; i < cfg->centers.size(); i++) {
qreal x = cfg->centers[i].first * background_.width();
qreal y = cfg->centers[i].second * background_.height();
MapSymbol* item = new MapSymbol(x, y, 10);
symbols_.append(item);
scene()->addItem(item);
}
/* (b) */
update();
}
Questions
Now all items except the 'bg_pixmap_' got displayed, and I checked the 'background_' variable that it loads the image correctly. Is there anything I missed?
How do I implement the resizeEvent of MyView to cope with the desired 'resize-strategy'?

What is the right way to scale a Flex application up to fullscreen?

Fullscreen mode and I have been battling for a while in this Flex application, and I'm coming up short on Google results to end my woes. I have no problem going into fullscreen mode by doing a Application.application.stage.displayState = StageDisplayState.FULL_SCREEN;, but the rest of the content just sits there in the top, left corner at it's original size.
All right, says I, I'll just do a stage.scaleMode = StageScaleMode.SHOW_ALL and make it figure out how to pull this off. And it looks like it does. Except that when you mouse over the individual checkboxes and buttons and various components, they all fidget slightly. Just a slight jump up or down as they resize...on mouse over. Well, this is frustrating, but bearable. I can always just invoke invalidateSize() explicitly for all of them.
But for the comboboxes. The ones at the bottom have their menus go off the bottom of the screen, and when I pop out of fullscreen mode, their drop downs cut off half way. I have no idea how to fix that. Can someone step in here, and put me out of my misery?
What is the right way to scale a Flex application up to fullscreen?
var button:Button = button_fullscreen;
try {
if(stage.displayState == StageDisplayState.FULL_SCREEN) {
Application.application.stage.displayState = StageDisplayState.NORMAL;
button.label = "View Fullscreen Mode";
stage.scaleMode = StageScaleMode.NO_SCALE;
} else {
Application.application.stage.displayState = StageDisplayState.FULL_SCREEN;
button.label = "Exit Fullscreen Mode";
stage.scaleMode = StageScaleMode.SHOW_ALL;
}
invalidateSizes(); // Calls invalidateSize() explicitly on several components.
} catch(error:SecurityError) {
Alert.show("The security settings of your computer prevent this from being displayed in fullscreen.","Error: "+error.name+" #"+error.errorID);
} catch(error:Error) {
Alert.show(error.message,error.name+" #"+error.errorID);
}
Sometimes things go wrong with flex :)
try the following approach
stage.align = StageAlign.TOP_LEFT;
then on resize or added to stage set the scaling manually
private function updateScaling():void
{
if(stage.stageWidth != width || stage.stageHeight != height)
{
var scaling:Number = 1;
if(width>height)
{
scaling = stage.stageWidth / width;
}
else
{
scaling = stage.stageHeight / height;
}
scaleX = scaleY = scaling;
}
}

Resources