Adding a header to a QListView - c++11

I encountered a little problem with QListView. I wanted to add a header to this object. However, I found no method to do such a task. I have seen several posts on SO and Qt forums but did not found anything relevant to my needs. I remembered that, in the past, I have used something that could be adapted to QListView (I think it was inspired by a Qt example but do not remember which one).
For those who need to display a header on the top of the QListView, I will post the code here. If someone find something false, or unadapted, please let me know. Here is the code:
Header
class MainMenuListView : public QListView
{
Q_OBJECT
class Header : public QWidget
{
public:
Header(MainMenuListView* parent);
QSize sizeHint() const;
protected:
void paintEvent(QPaintEvent* event);
private:
MainMenuListView* menu;
};
public:
MainMenuListView(QWidget* parent = nullptr, const QString& header = QString("Header"));
void headerAreaPaintEvent(QPaintEvent *event);
int headerAreaWidth();
protected:
void resizeEvent(QResizeEvent* event);
private:
QWidget* headerArea;
QString headerText;
};
Implementation
MainMenuListView::Header::Header(MainMenuListView* parent) : QWidget(parent), menu(parent) {}
QSize MainMenuListView::Header::sizeHint() const
{
return QSize(menu->headerAreaWidth(), fontMetrics().height());
}
void MainMenuListView::Header::paintEvent(QPaintEvent* event)
{
menu->headerAreaPaintEvent(event);
}
MainMenuListView::MainMenuListView(QWidget* parent, const QString& header) : QListView(parent), headerText(header)
{
headerArea = new Header(this);
setViewportMargins(0, fontMetrics().height(), 0, 0);
}
void MainMenuListView::headerAreaPaintEvent(QPaintEvent* event)
{
QPainter painter(headerArea);
painter.fillRect(event->rect(), Qt::lightGray);
painter.setPen(Qt::black);
painter.drawText(0, 0, headerArea->width(), fontMetrics().height(), Qt::AlignCenter, headerText);
}
int MainMenuListView::headerAreaWidth()
{
return width();
}
void MainMenuListView::resizeEvent(QResizeEvent* event)
{
QListView::resizeEvent(event);
headerArea->adjustSize();
}
Tested and working under Debian Qt5.x.x
Result:

Related

Undefined reference to xx::xx()

Believe me when I tell you that I searched online, but did not find the answer.
I have 5 files:
main.cpp
Game.cpp
Game.hpp
Window.cpp
Window.hpp
The content is below :
#include "Window.hpp"
#include "Game.hpp"
int main()
{
// Program entry point
Game game;
while (!game.GetWindow()->IsDone()){
// game loop here
game.HandleInput();
game.Update();
game.Render();
}
return 0;
}
This is the Game.cpp
#include "Window.hpp"
class Game {
public:
Game(): m_window("Chapter 2", sf::Vector2u(800,600)) {
m_mushroomTexture.loadFromFile("images.png");
m_mushroom.setTexture(m_mushroomTexture);
}
~Game(){}
void HandleInput() {
}
void Update() {
m_window.Update();
MoveMushroom();
}
void Render() {
m_window.BeginDraw();
m_window.Draw(m_mushroom);
m_window.EndDraw();
}
// Getting a point to the window
Window* GetWindow(){
}
private:
void MoveMushroom(){
sf::Vector2u l_windSize = m_window.GetWindowSize();
sf::Vector2u l_textSize = m_mushroomTexture.getSize();
if ((m_mushroom.getPosition().x > l_windSize.x - l_textSize.x and m_increment.x > 0) or \
(m_mushroom.getPosition().x < 0 and m_increment.x < 0)) {
m_increment.x = -m_increment.x;
}
if ((m_mushroom.getPosition().y > l_windSize.y - l_textSize.y and m_increment.y > 0) or \
(m_mushroom.getPosition().y < 0 and m_increment.y < 0)) {
m_increment.y = -m_increment.y;
}
m_mushroom.setPosition( m_mushroom.getPosition().x + m_increment.x, m_mushroom.getPosition().y + m_increment.y);
}
Window m_window;
sf::Texture m_mushroomTexture;
sf::Sprite m_mushroom;
sf::Vector2i m_increment;
};
Game.hpp
#pragma once
#include "Window.hpp"
#include <SFML/Graphics.hpp>
class Game {
public:
Game();
~Game();
void HandleInput();
void Update();
void Render();
// Getting a point to the window
Window* GetWindow();
private:
void MoveMushroom();
Window m_window;
sf::Texture m_mushroomTexture;
sf::Sprite m_mushroom;
sf::Vector2i m_increment;
};
Window.cpp
#include <SFML/Graphics.hpp>
#include <string>
class Window {
public:
// constructor
Window() {Setup("Window", sf::Vector2u(640,480));}
// we have 2 constructors because there 2 ways to instantiate a class
Window(const std::string& l_title, const sf::Vector2u& l_size) {
Setup(l_title, l_size);
}
~Window() { Destroy(); }
void BeginDraw(){
m_window.clear(sf::Color::Black);
}
void EndDraw(){
m_window.display();
}
void Update(){
sf::Event event;
while (m_window.pollEvent(event)) {
if (event.type == event.Closed) {
m_isDone = true;
} else if (event.type == sf::Event::KeyPressed and event.key.code == sf::Keyboard::F5){
ToggleFullscreen();
}
}
}
bool IsDone(){
return m_isDone;
}
bool IsFullscreen(){
return m_isFullscreen;
}
sf::Vector2u GetWindowSize() {
return m_windowSize;
}
void ToggleFullscreen(){
m_isFullscreen = !m_isFullscreen;
Destroy();
Create();
}
void Draw(sf::Drawable& l_drawable){
m_window.draw(l_drawable);
}
private:
void Setup(const std::string& l_title, const sf::Vector2u& l_size) {
m_windowTitle = l_title;
m_windowSize = l_size;
m_isFullscreen = false;
m_isDone = false;
Create();
}
void Destroy(){
m_window.close();
}
void Create() {
// the same as
// if (m_isFullscreen) {
// auto_style = sf::Style::Fullscreen;
// } else {
// auto_style = sf::Style::Default;
// }
auto style = (m_isFullscreen ? sf::Style::Fullscreen : sf::Style::Default);
m_window.create({m_windowSize.x, m_windowSize.y, 32}, m_windowTitle, style);
}
sf::RenderWindow m_window;
sf::Vector2u m_windowSize;
std::string m_windowTitle;
bool m_isDone;
bool m_isFullscreen;
};
Window.hpp
#pragma once
#include <SFML/Graphics.hpp>
#include <string>
class Window {
public:
// constructor
Window();
// we have 2 constructors because there 2 ways to instantiate a class
Window(const std::string& l_title, const sf::Vector2u& l_size);
~Window();
void BeginDraw();
void EndDraw();
void Update();
bool IsDone();
bool IsFullscreen();
sf::Vector2u GetWindowSize();
void ToggleFullscreen();
void Draw(sf::Drawable& l_drawable);
private:
void Setup(const std::string& l_title, const sf::Vector2u& l_size);
void Destroy();
void Create();
sf::RenderWindow m_window;
sf::Vector2u m_windowSize;
std::string m_windowTitle;
bool m_isDone;
bool m_isFullscreen;
};
The problem is that when i try to build my project i get a linker error.
/tmp/ccxbe5nA.o: In function `main':
main.cpp:(.text+0x26): undefined reference to `Game::Game()'
main.cpp:(.text+0x35): undefined reference to `Game::GetWindow()'
main.cpp:(.text+0x3d): undefined reference to `Window::IsDone()'
main.cpp:(.text+0x53): undefined reference to `Game::HandleInput()'
main.cpp:(.text+0x62): undefined reference to `Game::Update()'
main.cpp:(.text+0x71): undefined reference to `Game::Render()'
main.cpp:(.text+0x87): undefined reference to `Game::~Game()'
main.cpp:(.text+0xac): undefined reference to `Game::~Game()'
collect2: error: ld returned 1 exit status
I am compiling first with the following command :
g++ -std=c++11 -c main.cpp Window.cpp Game.cpp
No errors during the compilation stage. When I try to link it, I get the error message from above. The command used is this :
g++ main.o Game.o Window.o -o sfml-app -lsfml-graphics -lsfml-window -lsfml-system
By defining the same class differently in different places, your program violates One Definition Rule:
[basic.def.odr]/5 There can be more than one definition of a class type ... in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then
— each definition of D shall consist of the same sequence of tokens; and...
Emphasis mine.
Remove class definition from Game.cpp, only leave member function definitions, like this:
Game::Game(): m_window("Chapter 2", sf::Vector2u(800,600)) {...}
void Game::Update() {...}
// and so on for other members
And similarly for Window.
You define each class twice, which is incorrect.
In your .cpp files it needs to provide definitions for functions declared but not defined in the headers.
E.g., Windows.cpp should include Windows.hpp and contain:
bool Windows::IsDone() {
return m_isDone;
}

C++/CLI marshaling .NET delegate to native delegate

I am trying to pass a delegate with managed parameters to native code to be invoked. My code below runs ok, but the string output is garbage.
Native Class
Header
#pragma once
typedef void (* SegmentCreatedDelegate)(char** arg);
public class SampleClass
{
public:
SampleClass(void);
~SampleClass(void);
void DoWork(SegmentCreatedDelegate callback);
};
Code
SampleClass::SampleClass(void)
{
}
SampleClass::~SampleClass(void)
{
}
void SampleClass::DoWork(SegmentCreatedDelegate callback)
{
for(int x = 0; x< 10; x++)
{
char* myStr2 = "newsegment!";
callback(&myStr2);
}
}
Managed Class
Header
#pragma once
public ref class SampleClassNet
{
public:
delegate void SegmentCreatedDelegateNet(System::String^ arg);
SampleClassNet(void);
void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};
Code
SampleClassNet::SampleClassNet(void)
{
}
void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback)
{
SampleClass* nativeClass = new SampleClass();
System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(segmentCreatedCallback);
nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
System::GC::KeepAlive(segmentCreatedCallback);
}
This code runs fine with the follow c#.
var sampleClass = new SampleClassNet();
sampleClass.DoWork((Console.WriteLine));
Except I get the following output, instead of the expected 10 entries of "newsegment!".
(ÇÆX
(ÇÆX☺
(ÇÆX☻
(ÇÆX♥
(ÇÆX♦
(ÇÆX♣
(ÇÆX♠
(ÇÆX
(ÇÆX
(ÇÆX
Not exactly "newsegment!", but I am not sure why the marshaling is not working. Maybe I need I need some kind of "MarshalAs" attribute so that the System::String knows that I have 8-bit chars?
As mentioned in the comments, you should convert the char** to a String^. (Btw, why pass char**, not char*? String has a constructer taking char*, which might simplify things a lot.)
I haven't tried the following, but you might give it a try:
public ref class SampleClassNet {
private:
delegate void SegmentCreatedDelegateNative(char** str);
SegmentCreatedDelegateNet^ managedCallback;
SegmentCreatedDelegateNative^ nativeCallback;
void printString(char** string);
public:
delegate void SegmentCreatedDelegateNet(System::String^ arg);
SampleClassNet();
void DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback);
};
SampleClassNet::SampleClassNet() {
nativeCallback = printString;
}
void SampleClassNet::DoWork(SegmentCreatedDelegateNet^ segmentCreatedCallback) {
SampleClass* nativeClass = new SampleClass();
managedCallback = segmentCreatedCallback;
System::IntPtr pointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(nativeCallback);
nativeClass->DoWork((SegmentCreatedDelegate)(void*)pointer);
}
void SampleClassNet::printString(char** string) {
if (this->managedCallback != nullptr) {
String^ str = gcnew String(*string);
managedCallback(str);
}
}
The basic idea is to use another delegate, SegmentCreatedDelegateNative, handed to the native class, and to call the actual managed delegate from the function associated with the wrapper.

Fire an event in C++/CLI from unmanaged C / C++ function

I need to fire an event written in C++ / CLI from an unmanned function in c++.
What is the best way to do this?
Thanks in advance.
I figured out with some help from some help posts on codeproject
Thought of posting it here could be useful for others
#include "stdafx.h"
#include "windows.h"
using namespace System;
using namespace System::Runtime::InteropServices;
class Camera
{
public:
Camera()
{
}
~Camera(){}
void (*test)(void);
void OnNewCameraData();
void StartDataAcquisition();
};
void Camera::StartDataAcquisition()
{
int i;
while(i<10)
{
test();
i++;
Sleep(1000);
}
}
delegate void FunctionToCallDelegate();
ref class CameraAdapter
{
private:
Camera *_camera;
FunctionToCallDelegate ^_Function;
public:
CameraAdapter(FunctionToCallDelegate ^handler)
{
_Function = handler;
}
void Init()
{
_camera = new Camera();
pin_ptr<FunctionToCallDelegate^> tmp = &_Function;
_camera->test = (void (__cdecl *)(void))(Marshal::GetFunctionPointerForDelegate(_Function).ToPointer());
_camera->StartDataAcquisition();
}
~CameraAdapter()
{
delete _camera;
_camera = 0;
}
void OnNewCameraData()
{
Console::WriteLine("Received Frame \n");
}
};
int main(array<System::String ^> ^args)
{
FunctionToCallDelegate ^dsi;
dsi += gcnew FunctionToCallDelegate(gcnew CameraAdapter(dsi), &CameraAdapter::OnNewCameraData);
CameraAdapter ^camera = gcnew CameraAdapter(dsi);
camera->Init();
Console::ReadKey();
return 0;
}

QGraphicsScene/QGraphicsView performance

I am using QGraphicsScene/QGraphicsView pair in my project
I have performance issue with this pair.
I added my custom graphics items to scene and displayed the contents with view. After that my custom graphics items paint method continuously called by scene(just like infinite loop). This makes %25 of CPU usage(approximately 400 items on scene). What may cause this behaviour?
Here is one my item implementation:
class LevelCrossingItem : public QGraphicsWidget
{
public:
LevelCrossingItem(QString _id,qreal _x,qreal _y);
~LevelCrossingItem();
QRectF boundingRect() const;
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget /* = 0 */);
void readStateBits();
bool isClosed();
bool isGateArmBroken();
bool isOpenedDuringRouteTanzimCompleted();
bool hasDataConsistencyWarning();
int type() const {return Type;}
private slots:
void setVisible(bool);
private:
enum {Type = FIELDLEVELCROSSING};
QString m_id;
QString m_source;
short m_closedState;
short m_brokenGateArmState;
short m_openedDuringRouteTanzimCompletedState;
short m_dataConsistencyWarningState;
QBitArray stateBitArray;
qreal x,y;
QSvgRenderer *renderer;
};
#include "levelcrossing.h"
LevelCrossingItem::LevelCrossingItem(QString _id,qreal _x,qreal _y):m_id(_id),x(_x),y(_y),stateBitArray(4)
{
m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
renderer = new QSvgRenderer;
setStateArray(stateBitArray);
setZValue(-0.5);
}
LevelCrossingItem::~LevelCrossingItem()
{
delete renderer;
}
void LevelCrossingItem::setVisible(bool visible)
{
QGraphicsItem::setVisible(visible);
}
QRectF LevelCrossingItem::boundingRect() const
{
return QRectF(QPointF(x,y),sizeHint(Qt::PreferredSize));
}
QSizeF LevelCrossingItem::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
return QSizeF(50,270);
}
void LevelCrossingItem::readStateBits()
{
m_closedState = property("Closed").toInt();
m_brokenGateArmState = property("Broken").toInt();
m_openedDuringRouteTanzimCompletedState = property("OpenedOnRouteWarning").toInt();
m_dataConsistencyWarningState = property("DataConsistencyWarning").toInt();
stateBitArray.setBit(0,qvariant_cast<bool>(m_closedState));
stateBitArray.setBit(1,qvariant_cast<bool>(m_brokenGateArmState));
stateBitArray.setBit(2,qvariant_cast<bool>(m_openedDuringRouteTanzimCompletedState));
stateBitArray.setBit(3,qvariant_cast<bool>(m_dataConsistencyWarningState));
setStateArray(stateBitArray);
}
void LevelCrossingItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
{
Q_UNUSED(option);
Q_UNUSED(widget);
readStateBits();
m_closedState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("closed")
: m_source = LEVELCROSSING_RESOURCE_PATH.arg("open");
m_brokenGateArmState == Positive ? m_source = LEVELCROSSING_RESOURCE_PATH.arg("broken")
: m_source = m_source;
if(m_openedDuringRouteTanzimCompletedState == Positive)
{
setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),true);
if(stateChanged())
emit itemAlarmOccured(m_id,LevelCrossingIsOpenDuringTanzimCompleted);
}
else
setWarningVisible(OOR_WRN.arg(name()).arg(interlockingRegionId()),false);
if(m_dataConsistencyWarningState == Positive)
{
setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),true);
if(stateChanged())
emit itemAlarmOccured(m_id,LevelCrossingDataConsistency);
}
else
setWarningVisible(DC_WRN.arg(name()).arg(interlockingRegionId()),false);
renderer->load(m_source);
renderer->render(painter,boundingRect());
}
bool LevelCrossingItem::isClosed()
{
return m_closedState == Positive;
}
bool LevelCrossingItem::isGateArmBroken()
{
return m_brokenGateArmState == Positive;
}
bool LevelCrossingItem::isOpenedDuringRouteTanzimCompleted()
{
return m_openedDuringRouteTanzimCompletedState == Positive;
}
bool LevelCrossingItem::hasDataConsistencyWarning()
{
return m_dataConsistencyWarningState == Positive;
}
I read x and y coordinates from xml file. For this item x and y coordinates are 239,344 respectively
Most likely your graphics item has mistakes in the implementation. I had similar behavior, but I was unable to figure out what exactly causes it. I suspect that this happens when you draw outside of the bounding rect. This triggers some clean up routine, which in turn causes redraw of the item, and here goes the loop. Eventually I resolved the issue by carefully inspecting the implementation of my custom graphics item and making sure that:
These is no painting outside of the MyGraphicsItem::boundingRect. Use painter->setClipRect(boundingRect())
MyGraphicsItem::shape does not cross with the MyGraphicsItem::boundingRect.
If you override any other QGraphicsItem functions, make sure that your implementation is correct.
Hope this helps. Feel free to post the source code of your graphics item, it will be easier to find the problem.

How to use boost::bind in C++/CLI to bind a member of a managed class

I am using boost::signal in a native C++ class, and I now I am writing a .NET wrapper in C++/CLI, so that I can expose the native C++ callbacks as .NET events. When I try to use boost::bind to take the address of a member function of my managed class, I get compiler error 3374, saying I cannot take the address of a member function unless I am creating a delegate instance. Does anyone know how to bind a member function of a managed class using boost::bind?
For clarification, the following sample code causes Compiler Error 3374:
#include <boost/bind.hpp>
public ref class Managed
{
public:
Managed()
{
boost::bind(&Managed::OnSomeEvent, this);
}
void OnSomeEvent(void)
{
}
};
While your answer works, it exposes some of your implementation to the world (Managed::OnSomeEvent). If you don't want people to be able to raise the OnChange event willy-nilly by invoking OnSomeEvent(), you can update your Managed class as follows (based on this advice):
public delegate void ChangeHandler(void);
typedef void (__stdcall *ChangeCallback)(void);
public ref class Managed
{
public:
Managed(Native* Nat);
~Managed();
event ChangeHandler^ OnChange;
private:
void OnSomeEvent(void);
Native* native;
Callback* callback;
GCHandle gch;
};
Managed::Managed(Native* Nat)
: native(Nat)
{
callback = new Callback;
ChangeHandler^ handler = gcnew ChangeHandler( this, &Managed::OnSomeEvent );
gch = GCHandle::Alloc( handler );
System::IntPtr ip = Marshal::GetFunctionPointerForDelegate( handler );
ChangeCallback cbFunc = static_cast<ChangeCallback>( ip.ToPointer() );
*callback = native->RegisterCallback(boost::bind<void>( cbFunc ) );
}
Managed::~Managed()
{
native->UnregisterCallback(*callback);
delete callback;
if ( gch.IsAllocated )
{
gch.Free();
}
}
void Managed::OnSomeEvent(void)
{
OnChange();
}
Note the alternate bind<R>() form that's used.
After googling some more, I finally found a nice blog post about how to do this. The code in that post was a little more than I needed, but the main nugget was to use a global free function that takes an argument of the managed this pointer wrapped in a gcroot<> template. See the SomeEventProxy(...) in the code below for an example. This function then turns around and calls the managed member I was trying to bind. My solution appears below for future reference.
#include <msclr/marshal.h>
#include <boost/bind.hpp>
#include <boost/signal.hpp>
#include <iostream>
#using <mscorlib.dll>
using namespace System;
using namespace msclr::interop;
typedef boost::signal<void (void)> ChangedSignal;
typedef boost::signal<void (void)>::slot_function_type ChangedSignalCB;
typedef boost::signals::connection Callback;
class Native
{
public:
void ChangeIt()
{
changed();
}
Callback RegisterCallback(ChangedSignalCB Subscriber)
{
return changed.connect(Subscriber);
}
void UnregisterCallback(Callback CB)
{
changed.disconnect(CB);
}
private:
ChangedSignal changed;
};
delegate void ChangeHandler(void);
public ref class Managed
{
public:
Managed(Native* Nat);
~Managed();
void OnSomeEvent(void);
event ChangeHandler^ OnChange;
private:
Native* native;
Callback* callback;
};
void SomeEventProxy(gcroot<Managed^> This)
{
This->OnSomeEvent();
}
Managed::Managed(Native* Nat)
: native(Nat)
{
native = Nat;
callback = new Callback;
*callback = native->RegisterCallback(boost::bind( SomeEventProxy, gcroot<Managed^>(this) ) );
}
Managed::~Managed()
{
native->UnregisterCallback(*callback);
delete callback;
}
void Managed::OnSomeEvent(void)
{
OnChange();
}
void OnChanged(void)
{
Console::WriteLine("Got it!");
}
int main(array<System::String ^> ^args)
{
Native* native = new Native;
Managed^ managed = gcnew Managed(native);
managed->OnChange += gcnew ChangeHandler(OnChanged);
native->ChangeIt();
delete native;
return 0;
}

Resources