let `QWebView` scroll horizontally on mouse wheel - qt

What's the easiest way to let a QWebView scroll horizontally instead of vertically on mouse wheel events. I can thinks of the following alternatives, but maybe there is some easier way:
subclass QWebView and reimplement QWebView::wheelEvent()
load some javascript on the displayed page which does the transformation

Another method is to send a faked wheel-event with orientation Horizontal.
void HScrollWebView::wheelEvent(QWheelEvent *ev)
{
QWheelEvent weHorizontal( ev->pos(), ev->delta(), ev->buttons(), ev->modifiers(),
Qt::Horizontal );
QWebView::wheelEvent( &weHorizontal );
}
This version also works for complex webpages. E.g. a webpage with a scrollable subsection will not scroll the correct area by calling
page()->currentFrame()->scroll(ev->delta(), 0);
if currentFrame() points at the wrong frame (e.g. the mainframe).

I overestimated the complexity of option 1. in my question. I've implemented it now, like this (omitted constructor):
class HScrollWebView : public QWebView
{
Q_OBJECT
public:
explicit HScrollWebView(QWidget *parent = 0);
protected:
virtual void wheelEvent(QWheelEvent *ev);
};
void HScrollWebView::wheelEvent(QWheelEvent *ev){
page()->currentFrame()->scroll(ev->delta(), 0);
}

Related

How to make QToolButton go beyond the edge of QToolbar?

How can I make the button go beyond the edge of QToolbar?
Below is the code as I create the toolbar:
mainwindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0)
private:
QToolBar* _toolBar;
};
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
_toolBar = new QToolBar;
QAction *actionAdd = new QAction(QIcon(":/images/add.png"), "", this);
_toolBar->addAction(actionAdd);
addToolBar(Qt::ToolBarArea::TopToolBarArea, _toolBar);
}
style.qss
QToolBar {
background: #018ac4;
height: 150px;
}
As said before, it is not possible to solve this correctly using QtWidgets.
However I see two options to visually create that effect:
Take the button out of the tool bar and add it to the main window instead, but do not add it to a layout. Usually i would say reposition it on resize events, but since it is in the top left, you might as well just call setGeometry() once on startup and not worry about it later. You probably have to add last, or call rise() though.
Make it look like the button sticks out, while it really doesn't. Make the toolbar as large as the button, but paint the lower part of the toolbar in the brighter blue, so that it looks like it is part of the widget below it.
It is not possible with widgets. A QWidget can not paint outside of its area. See this answer : https://stackoverflow.com/a/48302076/6165833.
However, the QToolBar is not really the parent of the QAction because addAction(QAction *action) does not take the ownership. So maybe the QMainWindow could paint your QAction the way you want but AFAIK this is not doable through the public API of Qt.
What you could do is use QML (but you would need to use QML for the whole window then).

Overriding QLabel to be able to draw graphs

I want to draw a graph on my main form, so I figured I'd use a QLabel and Override that. Like this:
// drawlabel.h
class DrawLabel : public QLabel
{
Q_OBJECT
public:
DrawLabel(QWidget *parent = 0);
private:
void paintEvent(QPaintEvent *);
};
// drawlabel.cpp
DrawLabel::DrawLabel(QWidget *parent)
: QLabel(parent)
{
}
void DrawLabel::paintEvent(QPaintEvent *)
{
qDebug() << "paint event" ;
QPainter painter(this);
painter.setPen(QPen(QBrush(QColor(0,0,0,180)),1,Qt::DashLine));
painter.setBrush(QBrush(QColor(255,255,255,120)));
QRect selectionRect(10, 10, 100, 101);
painter.drawRect(selectionRect);
}
On my main window I droppde a QLabel, sized it to about 500x200 and promoted it to DrawLLabel. When the application is run, a dashed square is drawn on the form.
All good so far.
If I add the line:
this->setText("123456");
into the DrawLabel constructor, or add it into the paintEvent() I don't see the text. I'd also like to be able to have a border around the DrawLabel, but
this->setFrameShape(QFrame::Box);
in the constructor doesn't work either.
What should I be doing to get these to work?
Well, I think you should call paintEvent of base class. Add parameter name e to method:
void DrawLabel::paintEvent(QPaintEvent *e)
And then at end of method add
QLabel::paintEvent (e);
The second option do all painting by yourself directly at paintEvent.
If you want something custom, then implement a custom widget inheriting QWidget. Then you get to draw whatever you want and have whatever members you want.
Your problem is you have overridden the label's paint event, so the code to draw the label text is not executed.
You could call the method from QLabel as Evgeny suggested, but it is better to implement a custom widget instead.
Calling the method from the base class might for example corrupt any previous drawing, unless the method was implemented with calling form derived classes in mind. I don't expect that is the case for stock widgets. I haven't tried doing it with QLabel re-implementations in particular, but I have tried it with other stock widgets and it did not work as expected.

How to disable the resize cursor

I use QWidget::setFixedSize to avoid my window being resized. Even though it works, the resize-style cursor still appears when passing over the edges.
Like this for example: http://bp3.blogger.com/_fhb-4UuRH50/R1ZMKyoIvMI/AAAAAAAAA6s/I08ntfXpp2k/s1600-h/w-resize.gif
Well, you know what I mean. How can I avoid that?
I use Windows 7 with the default windows manager.
If this is your mainwindow and you're using Qt 4, you can disable the sizegrip of your mainwindow's statusbar:
this->statusBar()->setSizeGripEnabled(false);
Otherwise you can set the Qt::MSWindowsFixedSizeDialogHint flag to your window:
this->setWindowFlags(this->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
First solution
You can add the following flag to the flags of your window to prevent the window from being resized by the user:
setWindowFlags(this->windowFlags() |= Qt::FramelessWindowHint);
Here is some more information about Window Flags.
Second (ugly) experiment solution
This is kind of a dirty work-around... I'm fully aware of the fact, that this is not clean.
I just wrote this little main window that changes the cursor manually when the main window's area is left.
Note: You have to consider side effects. Maybe there is another cursor shape needed for a child widget, but this overrides the cursor for the complete application.
This can be used as a starting point for further development and for simple applications.
Header:
class CMainWindow :
public QMainWindow
{
public:
CMainWindow(QWidget* parent = nullptr);
virtual ~CMainWindow(void);
protected:
virtual void leaveEvent( QEvent *event );
virtual void enterEvent( QEvent *event );
};
cpp:
CMainWindow::CMainWindow(QWidget* parent) : QMainWindow(parent)
{
setMouseTracking(true);
}
CMainWindow::~CMainWindow(void)
{
}
void CMainWindow::leaveEvent( QEvent *event )
{
qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
QMainWindow::leaveEvent(event);
}
void CMainWindow::enterEvent( QEvent *event )
{
qApp->restoreOverrideCursor();
QMainWindow::enterEvent(event);
}
Use
setMinimumSize(QSize(width_px,height_px))
setMaximumSize(QSize(width_px,height_px))
where both methods have same size.You won't see the resize cursor & the window thus doesn't get resized/maximized.

Qt menu without shadow?

I copied the question description below from other asked but not answered question, because this is the exactly the same one I wanna ask.
I have a QMenu with a translucent background and rounded edges (border-radius). Unfortunately, Windows 7 draws a drop shadow for this menu, which does not fit to the rounded edges. Its the shadow that would be drawn for normal rectangular menus.
Is there either - a way to completely disable drawing drop shadows for QMenu or - a way to make the shadow fit to the rounded edges ?
Here is a minimalistic example where it occurs:
QPushButton b("press me");
QMenu m;
m.addAction("hello"); m.addAction("world");
m.setWindowFlags(m.windowFlags() | Qt::FramelessWindowHint);
m.setAttribute(Qt::WA_TranslucentBackground);
m.setStyleSheet("background:rgba(255,0,0,50%); border-radius:5px;");
b.setMenu(&m);
b.show();
Right now I have to turn off the menu shadow in Windows Control panel manually to get rid of that shadow.
Actually what I want to achieve is a menu like Qt's pie menu or a menu like this one:
http://upload.wikimedia.org/wikipedia/commons/8/85/Blender_2.36_Screenshot.jpg
I tried the popup widget, but it gets the shadow artifact described above.
Could anyone help this out?
On Windows Vista and higher, I wanted a menu with normal window shadow. So I had to do two things:
Remove CS_DROPSHADOW from the menu HWND's WNDCLASS that Qt is adding deep down in the core.
Add shadow using DWM APIs.
The trick is to capture QEvent::WinIdChange to get the HWND handle to the menu window, and then to use GetClassLong / SetClassLong to remove CS_DROPSHADOW flag. I'm doing this only once (by using a static bool), as theWNDCLASS is always the same for all menus. This might lead into a problem if part of your app wants to show the menu shadows and other does not.
I have subclassed the QMenu and I'm always using my overriden class when creating menus
Menu * my_menu = new Menu(tr("&File"));
mainMenu->addMenu(my_menu);
Here's the whole code, enjoy:
menu.h
#ifndef MENU_H
#define MENU_H
#include <QMenu>
class Menu : public QMenu
{
Q_OBJECT
public:
explicit Menu(QWidget *parent = 0);
explicit Menu(const QString & title);
protected:
virtual bool event(QEvent *event);
signals:
public slots:
};
#endif // MENU_H
menu.cpp
#include "menu.h"
#pragma comment( lib, "dwmapi.lib" )
#include "dwmapi.h"
Menu::Menu(QWidget *parent) :
QMenu(parent)
{
}
Menu::Menu(const QString &title) :
QMenu(title)
{
}
bool Menu::event(QEvent *event)
{
static bool class_amended = false;
if (event->type() == QEvent::WinIdChange)
{
HWND hwnd = reinterpret_cast<HWND>(winId());
if (class_amended == false)
{
class_amended = true;
DWORD class_style = ::GetClassLong(hwnd, GCL_STYLE);
class_style &= ~CS_DROPSHADOW;
::SetClassLong(hwnd, GCL_STYLE, class_style);
}
DWMNCRENDERINGPOLICY val = DWMNCRP_ENABLED;
::DwmSetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &val, sizeof(DWMNCRENDERINGPOLICY));
// This will turn OFF the shadow
// MARGINS m = {0};
// This will turn ON the shadow
MARGINS m = {-1};
HRESULT hr = ::DwmExtendFrameIntoClientArea(hwnd, &m);
if( SUCCEEDED(hr) )
{
//do more things
}
}
return QWidget::event(event);
}
I just remove the Qt::popup flag to get rid of the shadow.
And I have to add close codes to any other background UI. These have been more extra work, but I got what I want :)

Copy Bits to QtImage in QGLWidget

Maybe someone can help me with the following problem:
I want to draw the content of a QImage in a QGLWidget, but the widget is painted in black.
class QGLCanvas {
public:
QGLCanvas(QWidget* parent) : QGLWidget(parent) {
}
void setImage(const QImage* image) {
img = image;
}
void paintEvent(QPaintEvent*) {
// From Painter Documentation Qt
QPainter p(this);
p.setRenderHint(QPainter::SmoothPixmapTransform, 1);
p.drawImage(this->rect(), *img);
p.end();
}
public slots:
void rgb_data(const void *data) {
memcpy((void *)img->bits(), data, img->byteCount()); // data will be copied (sizes are known)
// img.save("text.png"); // saves right image
this->update(); // calls repaint, but does not draw the image.
}
private:
QImage *img;
}
The Bug:
When the slot is called, the memory is copied to the image. If the image is saved, the content is correct. But the repaint method just draws black content to the widget.
The Fix:
If the memcpy line is implemented outside the slot, the image content is drawn to the widget. This fix increased code complexity a lot. Thus, i've got the following question:
The Question:
Why does the memcpy not work within the slot? Is this a general problem with Qt?
There's nothing special about a slot which would stop your code from working.
What's probably the issue is that when you call update(), a repaint is scheduled but happens asynchronously. From the code you've provided the most likely cause is img being modified between the calls to rbg_data and paintEvent
You want to be sure about the format of the QImage. When you call bits and are expecting it to be RGB, you need to check the format.
if( img->format() != QImage::Format_RGB888 )
{
// convert the image format to RGB888
*img = img->convertToFormat(QImage::Format_RGB888);
}
This way, Qt will know the image format when trying to paint it. If you fill it with RGB data but the QImage is "formatted" as ARGB, you will get some painting errors.

Resources