Transparent wxPanel member in wxFrame - c++

I have a MainFrame which is derived from wxFrame. The frame has a panel member m_panel of a custom class, derived from wxPanel.
I overloaded the OnPaint() function of the MainFrame to set a background image.
From the background image I only see a 5 pixel boarder. The rest is blocked by the wxPanel. And for some reason I cannot make the panel transparent. I tried m_panel->Hide() which had no effect at all and m_panel->SetBackgroundStyle(wxBG_STYLE_CUSTOM). The latter had the weird effect that I could see the desktop (however the background image was still visible in the 5px border).
I did add the wxTRANSPARENT_WINDOW style in the constructor of the wxPanel.
How can I have this panel and make it transparent?

Have a custom wxPanel where you override OnPaint to have your drawings. Then use this as the main panel of your wxFrame. Example shown below:
class BackgroundPanel: public wxPanel
{
public:
BackgroundPanel(wxFrame* parent);
void OnPaint(wxPaintEvent & evt);
private:
wxBitmap backgroundBitmap;
DECLARE_EVENT_TABLE()
};
BackgroundPanel::BackgroundPanel(wxFrame* parent)
:wxPanel(parent)
{
//Set backgroundBitmap
}
void BackgroundPanel::OnPaint(wxPaintEvent& evt)
{
wxPaintDC dc(this);
int height = GetClientRect().GetHeight() - backgroundBitmap.GetHeight();
dc.DrawBitmap(backgroundBitmap,0,height,false);
}

Related

MFC: How do I change background color in MFC?

By default the color is gray, I want to change it.I use OnEraseBkgnd in my MainFarm.h,this works, it changes color,but when somewhere further in the code mfc changes it to gray again.
BOOL CMainFrame::OnEraseBkgnd(CDC* pDC)
{
CBrush backBrush(RGB(0, 0, 0));
CBrush* pPrevBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect);
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),
PATCOPY);
pDC->SelectObject(backBrush);
return TRUE;
}
A MDI application doesn't just have frame windows and child windows. It also has a client window. The client window handles most of managing child windows.
But it also draws the client area of the frame window. This is what's drawing the grey background after you draw your background when you handle OnEraseBkgnd in the frame window.
Assuming your frame is derived from CMDIFrameWndEx, you should have a OnEraseMDIClientBackground virtual function that you can override to do the drawing you want.
If you're modifying older code, it's possible it uses an old enough version of MFC that's not present. If so, you need to create a window class and do the correct drawing in its onEraseBkgnd, create an instance of that in your frame window class, and in the frame window's onCreate, you subclass the MDI child window:
class MyBkgndErase : public CWnd {
public:
BOOL OnEraseBkgnd(CDC* pDC) {
// drawing code here
}
};
class MyFrameWnd : public CMDIFrameWnd {
MyBkgndErase eraser;
int OnCreate(LPCREATESTRUCT lpCreateStruct) {
// there's probably existing code you'll want to preserve here
eraser.SubclassWindow(m_hWndMDIClient);
return 0;
}
};
Or, if you can switch to a newer version of MFC, you can probably just change your frame window's parent class from CMDIFrameWnd to CMDIFrameWndEx, and use OnEraseMDIClientBackground (which is undoubtedly easier).

Overlay multiple widgets

I have one QWidget which contains a multiple sliders. All sliders resized to main QWidget size. As result all sliders share same draw rectangle. For sliders I overload paintEvent method, so it draw only required stuff. Here is an example code:
class MySlider : public QSlider
{
void paintEvent(QPaintEvent *event) {
...
}
}
class MyWidget : public QWidget
{
MyWidget() : QWidget() {
slider1 = new MySlider(this);
slider2 = new MySlider(this);
slider1->resize(rect().width(), rect().height());
slider2->resize(rect().width(), rect().height());
}
MySlider * slider1;
MySlider * slider2;
}
adsf
Groove is not seen with this solution (because we don't call QSlider::paintEvent), but it still exist. For this widget it is possible to use only the last created slider (slider2). The rest are visible, but they are not available.
Is it possible to overlay multiple widgets on each other and still be able to access all of them with mouse event?
Overlapping widgets isn't a good idea, expect only one is visible at the same time. What is the purpose for that overlapping?
You can set QWidget::setAttribute(Qt::WA_TransparentForMouseEvents) to not generate any mouse events for that particular widget so that only one slider will get that events. Then you are able to redirect that messages to your other sliders.

Paint over top of label, not behind it in Qt

I am creating a simple gauge in Qt 4.7.4, and everything is working wonderfully. Except for the fact that, for the life of me, I cannot get the dial shape to paint over the text labels when it passes over them. It always paints it behind the label. I am just using a simple drawpolygon() method.
I'm thinking this has something to do about paint events? I am drawing everything inside a QFrame inside a MainWindow. I am using QFrame's paintEvent.
Edit:
The QLabels are created on start up with new QLabel(this). They are only created once, and never touched again ( Similar to manually adding them on the Ui with Designer). The drawpolygon() is in the QFrame's Paint event.
"myclass.h"
class gauge : public QFrame
{
Q_OBJECT
public:
explicit gauge(QWidget *parent = 0);
~gauge();
void setValues(int req, int Limit, bool extra=false);
private:
void drawDial();
protected:
void paintEvent(QPaintEvent *e);
};
"myclass.cpp"
void gauge::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
drawDial();
return;
}
void gauge::drawDial()
{
QPainter Needle(this);
Needle.save();
Needle.setRenderHint(Needle.Antialiasing, true); // Needle was Staggered looking, This will make it smooth
Needle.translate(centrePt); // Center of Widget
Needle.drawEllipse(QPoint(0,0),10,10);
Needle.restore();
Needle.end();
}
If the gauge widget and the QLabels are siblings, then you can move the gauge widget to the front by calling its raise() method.
If the QLabels are children of the gauge widget, on the other hand, then they will always display in front of it. In that case you can either reorganize your widget hierarchy so that they are siblings instead, or you can get rid of the QLabels and simply call drawText() from your paintEvent() method instead (after drawDial() returns)

Can i call a single document MFC from dialog MFc?

i have to draw something in dialog box mfc , so , can i call a single document (because i know how to draw in single document MFC ) , from my main dialog box ?
thnx
You can use the same drawing code both in a CView and in a CDialog.
On the CView drawing works like this:
void CMyView::OnDraw(CDC* pdc)
{
// Draw something on pdc
Draw(pdc);
}
In a CDialog, override the OnPaint() handler, and draw like this:
void CMyDialog::OnPaint()
{
CPaintDC dc(this);
CPaintDC* pdc = &dc;
CDialog::OnPaint();
// Draw something on pdc
Draw(pdc);
}
Instead of a view in a dialog box, use a window derived from CStatic and make it to the size of dialog box on OnSize. It will be better than adding a view in a dialog box.
You have to override the OnPaint() event of the static control. To avoid flicker you have to override OnEraseBkgrnd() event.
class CMyStatic : public CStatic
{
public:
CMyStatic ()
~CMyStatic();
protected:
afx_msg void OnPaint();
void Draw(CDC *pDC);
};
void CMyStatic::Draw(CDC *pDC)
{
}
void CMyStatic::OnPaint()
{
CPaintDC dc(this);
Draw(&dc);
}

QRubberBand like feature - Static selection area

I'm trying to draw a selection area on top of the desktop/opened windows, which works well by using QRubberBand, but seeing as it does not have a stylesheet command, how would I be able to change the color and width of the border and making the inside of it completely transparent?
Edit: Is there a similar method to use than QRubberBand in Qt? Changing the painter methods gives a lot of problems (border is one pixel larger on the left and top than right and bottom, the marked area seems not to be able to be completely transparent).
Edit2: The area it will cover is static, not something that is dragged by the user.
Edit3:
class CustomRubberBand : public QRubberBand
{
public:
CustomRubberBand(Shape s, QWidget * p = 0) : QRubberBand(s, p)
{
}
protected:
void paintEvent(QPaintEvent *pe)
{
Q_UNUSED(pe);
QPainter painter;
QPen pen(Qt::red, 6);
pen.setStyle(Qt::SolidLine);
painter.begin(this);
painter.setPen(pen);
painter.drawRect(pe->rect());
painter.end();
}
};
This gives me the border around it that I want, but I haven't found anything about removing the background (completely transparent) that works... Seems like there is a problem with Vista and Qt with this.
Any tips on how to remove the background? Right now with no painting method for it it is a semi-transparent white background instead of the default blue one.
Edit4:
This shows the problem: Visible background error notice how the background, with the border, is a semi transparent white. The paint method I'm using does not draw this but only the border. I want it to be completely invisible, and setting the opacity for the object will also make the border transparent, which it should not be.
You can use a transparent QPalette in the paintEvent function to achieve what you are trying to do.
class ScreenViewport : public QRubberBand
{
Q_OBJECT
public:
ScreenViewport(Shape shape, QWidget *parent = 0) : QRubberBand(shape,parent){
}
protected:
void paintEvent(QPaintEvent *pe){
pal = new QPalette(Qt::transparent);
setPalette(*pal);
Q_UNUSED(pe);
QPainter painter;
QPen pen(Qt::red, 6);
pen.setStyle(Qt::DashLine);
painter.begin(this);
painter.setPen(pen);
painter.drawRect(pe->rect());
painter.end();
}
private:
QPalette *pal;
};
QRubberBand inherits from QWidget which in turn supports setStyleSheet function, see the QRubberBand member functions listing.
If this is not working right for you just override ::paintEvent , see this example.