Is there another class besides QWidget which holds all generic functions for both? Something like QEdit...
As an example I'd like to reference cut(), copy() and paste(), but it looks like I have to dynamic cast the QWidget. Is there any other way?
There is no other way besides QWidget. The reason is that QLineEdit is inherited directly from QWidget. You can see the full hierarchy of Qt classes here
You don't have to dynamic-cast anything: this is typically a sign of bad design. Qt generally has very few interface classes - they usually have the word Abstract somewhere in the name, and are not really pure interfaces as they have non-abstract base classes, like e.g. QObject. Thus there was no pattern to follow, and no need for abstracting out the edit operations into an interface.
There are several approaches to overcome this:
Leverage the fact that the methods in question are known by the metaobject system. Note that invokeMethod takes a method name, not signature.
bool cut(QWidget * w) {
return QMetaObject::invokeMethod(w, "cut");
}
bool copy(QWidget * w) {
return QMetaObject::invokeMethod(w, "copy");
}
//...
You can use the free-standing functions such as above on any widget that supports the editing operations.
As above, but cache the method lookup not to pay its costs repeatedly. Note that indexOfMethod takes a method signature, not merely its name.
static QMetaMethod lookup(QMetaObject * o, const char * signature) {
return o->method(o->indexOfMethod(signature));
}
struct Methods {
QMetaMethod cut, copy;
Methods() {}
explicit Methods(QMetaObject * o) :
cut(lookup(o, "cut()")),
copy(lookup(o, "copy()")) {}
Methods(const Methods &) = default;
};
// Meta class names have unique addresses - they are effectively memoized.
// Dynamic metaobjects are an exception we can safely ignore here.
static QMap<const char *, Methods> map;
static const Methods & lookup(QWidget * w) {
auto o = w->metaObject();
auto it = map.find(o->className());
if (it == map.end())
it = map.insert(o->className(), Methods(o));
return *it;
}
bool cut(QWidget * w) {
lookup(w).cut.invoke(w);
}
bool copy(QWidget * w) {
lookup(w).copy.invoke(w);
}
//...
Define an interface and provide implementations specialized for widget types. This approach's only benefit is that it's a bit faster than QMetaMethod::invoke. It makes little sense to use this code for clipboard methods, but it could be useful to minimize overhead for small methods that are called very often. I'd advise not to over-engineer it unless a benchmark shows that it really helps. The previous approach (#2 above) should be quite sufficient.
// Interface
class IClipboard {
public:
virtual cut(QWidget *) = 0;
virtual copy(QWidget *) = 0;
virtual paste(QWidget *) = 0;
};
class Registry {
// all meta class names have unique addresses - they are effectively memoized
static QMap<const char *, IClipboard*> registry;
public:
static void register(const QMetaObject * o, IClipboard * clipboard) {
auto name = o->className();
auto it = registry.find(name);
if (it == registry.end())
registry.insert(name, clipboard);
else
Q_ASSERT(it->value() == clipboard);
}
static IClipboard * for(QWidget * w) {
auto it = registry.find(w->metaObject()->className());
Q_ASSERT(registry.end() != it);
return it->value();
}
static void unregister(const QMetaObject * o) {
registry.remove(o->className());
}
};
template <class W> class ClipboardWidget : public IClipboard {
Q_DISABLE_COPY(ClipboardWidget)
public:
cut(QWidget * w) override { static_cast<W*>(w)->cut(); }
copy(QWidget * w) override { static_cast<W*>(w)->copy(); }
paste(QWidget * w) override { static_cast<W*>(w)->paste(); }
ClipboardWidget() {
Registry::register(&W::staticMetaObject(), this);
}
~ClipboardWidget() {
Registry::unregister(&W::staticMetaObject());
}
};
// Implementation
QMap<const char *, IClipboard*> Registry::registry;
static ClipboardWidget<QTextEdit> w1;
static ClipboardWidget<QLineEdit> w2;
void yourCode() {
//...
Registry::for(widget)->cut(widget);
}
Related
I want to use the nlohmann/json library to serialize some json to a QObject and vice versa.
The problem I run into is that the parser is trying to use the copy constructor of the QObject, wish is not allowed.
There is something in the documentation regarding this https://github.com/nlohmann/json#how-can-i-use-get-for-non-default-constructiblenon-copyable-types but I can't manage to make it work.
template <>
struct adl_serializer<MyQObject>
{
static MyQObject from_json(const json& j)
{
return {j.get<MyQObject>()}; // call to implicitly-deleted copy constructor of 'MyQObject'
}
static void to_json(json& j, MyQObject t)
{
j = t; // no viable overload '='
}
};
inline void from_json(const json& j, MyQObject& x)
{
x.setXxx(j.at("xxx").get<typeOfXxx>()):
// ...
}
inline void to_json(json& j, const MyQObject& x)
{
j = json::object();
j["xxx"] = x.xxx();
// ...
}
What should I write in the adl_serializer to make it work ?
I am developing a library which has two layers, unmanaged (C++) and managed (C++/CLI). The unmanaged layer contains the logics and the computation algorithms, while the managed layer provides interface and visualisation to a .NET-based host application. A class in the managed layer wraps its class counterpart in the unmanaged layer, e.g. ManagedA wraps UnmanagedA and ManagedB wraps UnmanagedB.
Classes in the unmanaged layer have query methods, suppose UnmanagedA::B() returns an instance of UnmanagedB. For visualisation, I need to wrap this instance in a ManagedB instance. The problem is, if I repeat this process twice, I am creating two ManagedB instances which points to the same UnmanagedB instance. Because the ManagedB instances are disposed, the same UnmanagedB instance is deleted twice, which should not happen.
So I would like to know the best practice or strategy to wrap an unmanaged object in a managed object.
Here is a code which emulates this behaviour. I understand that you don't need to explicitly delete the managed objects, but I use it here just to emulate the deletion sequence.
Many thanks.
#include "stdafx.h"
using namespace System;
class UnmanagedB
{
public:
UnmanagedB() {}
~UnmanagedB() {}
int i = 0;
};
class UnmanagedA
{
public:
UnmanagedA(UnmanagedB* pUnmanagedB)
: m_pUnmanagedB(pUnmanagedB)
{
}
~UnmanagedA() {}
UnmanagedB* B() { return m_pUnmanagedB; }
protected:
UnmanagedB* m_pUnmanagedB;
};
public ref class ManagedA : IDisposable
{
public:
ManagedA(UnmanagedA* pUnmanagedA)
: m_pUnmanagedA(pUnmanagedA)
{
}
~ManagedA()
{
delete m_pUnmanagedA;
}
private:
UnmanagedA* m_pUnmanagedA;
};
public ref class ManagedB : IDisposable
{
public:
ManagedB(UnmanagedB* pUnmanagedB)
: m_pUnmanagedB(pUnmanagedB)
{
}
~ManagedB()
{
delete m_pUnmanagedB;
}
private:
UnmanagedB * m_pUnmanagedB;
};
int main(array<System::String ^> ^args)
{
UnmanagedB* pUnmanagedB = new UnmanagedB();
UnmanagedA* pUnmanagedA = new UnmanagedA(pUnmanagedB);
ManagedB^ pManagedB1 = gcnew ManagedB(pUnmanagedA->B());
ManagedB^ pManagedB2 = gcnew ManagedB(pUnmanagedA->B());
delete pManagedB1;
delete pManagedB2; // will crash here because the destructor deletes pUnmanagedB, which is already deleted in the previous line
delete pUnmanagedA;
return 0;
}
This is a typical case using a smart pointer.
So don't store UnmanagedA* and UnmanagedB* use shared_ptr and shared_ptr
Becaus ethe managed class can only carry a plain pointer to an unmannged class you have to redirect it again and use:
shared_ptr<UnmanagedA>* pManagedA;
A simple accessor function will help you to use the pointer:
shared_ptr<UnmanagedA> GetPtrA() { return *pManagedA; }
All plain pointer to the unmanaged classes should be shared_ptr instances. In your main use make_shared instead of new. Or direct the pointer created by new into a shared_ptr...
Here is one class rewritten:
public ref class ManagedA : IDisposable
{
public:
ManagedA(shared_ptr<UnmanagedA> pUnmanagedA)
{
m_pUnmanagedA = new shared_ptr<UnmanagedA>();
*m_pUnmanagedA = pUnmanagedA;
}
~ManagedA()
{
delete m_pUnmanagedA;
}
void Doit()
{
GetPtrA()->DoSomething();
}
private:
shared_ptr<UnmanagedA>* m_pUnmanagedA;
shared_ptr<UnmanagedA> GetPtrA() { return *m_pUnmanagedA; }
};
I have this base class:
// put the display in a macro on a .h file for less headache.
class Gadget {
protected:
int x, y;
U8GLIB * u8g;
virtual int f_focus() {return 0;};
virtual int f_blur() {return 0;};
virtual void f_draw() {};
virtual void f_select() {};
public:
Gadget(U8GLIB * u8g, int x, int y) :
u8g(u8g),
x(x),
y(y)
{
Serial.println(F("Gadget(U8GLIB * u8g, int x, int y)"));
};
Gadget() {
Serial.println(F("Gadget()"));
};
int focus(){return f_focus();};
int blur(){return f_blur();};
void draw(){f_draw();};
void operator()(){f_select();};
};
And this derived class:
class WakeUp :
public Gadget
{
public:
WakeUp(U8GLIB * u8g) :
Gadget(u8g, 0, 0)
{
Serial.println(F("WakeUp(U8GLIB * u8g)"));
};
};
Then I instantiate the WakeUp class inside an array like this:
Gadget gadgets[1] = {
WakeUp(&u8g)
};
Then I try to access this member like this:
void focus() {
Serial.println(gadgets[0].focus());
}
It is supposed to display 0. However it is displaying -64. Even if I override the f_focus() method on WakeUp class. If I remove the virtual specifier from f_focus() it works fine, displaying 0, but I will not be able to access the derived class implementation of this method.
I wish to understand what is causing this strange behavior and what can I do to avoid it.
EDIT:
The function runs fine if I call it from the Gadget Constructor.
You're slicing your WakeUp object.
You essentially have the following:
Gadget g = WakeUp(...);
What this code does is the following:
Construct a WakeUp object.
Call Gadget(const Gadget& other) with the base from the WakeUp object.
Destroy the temporary WakeUp object, leaving only the copy of the Gadget base.
In order to avoid this, you need to create an array of pointers (this is better if they are smart pointers).
Gadget* gadgets[1] = { new WakeUp(&u8g) }; // If you choose this method, you need to call
// delete gadget[0] or you will leak memory.
Using a pointer will correctly preserve the Gadget and WakeUp instances instead of slicing them away.
With smart pointers:
std::shared_ptr<Gadget> gadgets[1] = { std::make_shared<WakeUp>(&u8g) };
I'm trying to pass QList into QML using QQmlListProperty, as official documentation says:
QQmlListProperty::QQmlListProperty(QObject *object, void *data, CountFunction count, AtFunction at)
My code is:
QQmlListProperty<TTimingDriver> TTiming::getDrivers()
{
return QQmlListProperty<TTimingDriver>(this, &m_drivers, &TTiming::count, &TTiming::driverAt);
}
int TTiming::count(QQmlListProperty<TTimingDriver> *property)
{
TTiming * timing = qobject_cast<TTiming *>(property->object);
return timing->m_drivers.count();
}
TTimingDriver * TTiming::driverAt(QQmlListProperty<TTimingDriver> *property, int i)
{
TTiming * timing = qobject_cast<TTiming *>(property->object);
return timing->m_drivers.at(i);
}
But I'm getting an error:
no matching function for call to 'QQmlListProperty<TTimingDriver>::QQmlListProperty(TTiming*, QList<TTimingDriver*>*, int (TTiming::*)(QQmlListProperty<TTimingDriver>*), TTimingDriver* (TTiming::*)(QQmlListProperty<TTimingDriver>*, int))'
return QQmlListProperty<TTimingDriver>(this, &m_drivers, &TTiming::count, &TTiming::driverAt);
I think <ou are mixing two of the QQmlListProperty constructor overloads.
The one that takes the QList<T*> does not need pointers to functions.
So this should be sufficient
QQmlListProperty<TTimingDriver> TTiming::getDrivers()
{
return QQmlListProperty<TTimingDriver>(this, &m_drivers);
}
Assuming that m_drivers is of type QList<TTimingDriver*>
A very simple & quick question on Java libraries: is there a ready-made class that implements a Queue with a fixed maximum size - i.e. it always allows addition of elements, but it will silently remove head elements to accomodate space for newly added elements.
Of course, it's trivial to implement it manually:
import java.util.LinkedList;
public class LimitedQueue<E> extends LinkedList<E> {
private int limit;
public LimitedQueue(int limit) {
this.limit = limit;
}
#Override
public boolean add(E o) {
super.add(o);
while (size() > limit) { super.remove(); }
return true;
}
}
As far as I see, there's no standard implementation in Java stdlibs, but may be there's one in Apache Commons or something like that?
Apache commons collections 4 has a CircularFifoQueue<> which is what you are looking for. Quoting the javadoc:
CircularFifoQueue is a first-in first-out queue with a fixed size that replaces its oldest element if full.
import java.util.Queue;
import org.apache.commons.collections4.queue.CircularFifoQueue;
Queue<Integer> fifo = new CircularFifoQueue<Integer>(2);
fifo.add(1);
fifo.add(2);
fifo.add(3);
System.out.println(fifo);
// Observe the result:
// [2, 3]
If you are using an older version of the Apache commons collections (3.x), you can use the CircularFifoBuffer which is basically the same thing without generics.
Update: updated answer following release of commons collections version 4 that supports generics.
Guava now has an EvictingQueue, a non-blocking queue which automatically evicts elements from the head of the queue when attempting to add new elements onto the queue and it is full.
import java.util.Queue;
import com.google.common.collect.EvictingQueue;
Queue<Integer> fifo = EvictingQueue.create(2);
fifo.add(1);
fifo.add(2);
fifo.add(3);
System.out.println(fifo);
// Observe the result:
// [2, 3]
I like #FractalizeR solution. But I would in addition keep and return the value from super.add(o)!
public class LimitedQueue<E> extends LinkedList<E> {
private int limit;
public LimitedQueue(int limit) {
this.limit = limit;
}
#Override
public boolean add(E o) {
boolean added = super.add(o);
while (added && size() > limit) {
super.remove();
}
return added;
}
}
Use composition not extends (yes I mean extends, as in a reference to the extends keyword in java and yes this is inheritance). Composition is superier because it completely shields your implementation, allowing you to change the implementation without impacting the users of your class.
I recommend trying something like this (I'm typing directly into this window, so buyer beware of syntax errors):
public LimitedSizeQueue implements Queue
{
private int maxSize;
private LinkedList storageArea;
public LimitedSizeQueue(final int maxSize)
{
this.maxSize = maxSize;
storageArea = new LinkedList();
}
public boolean offer(ElementType element)
{
if (storageArea.size() < maxSize)
{
storageArea.addFirst(element);
}
else
{
... remove last element;
storageArea.addFirst(element);
}
}
... the rest of this class
A better option (based on the answer by Asaf) might be to wrap the Apache Collections CircularFifoBuffer with a generic class. For example:
public LimitedSizeQueue<ElementType> implements Queue<ElementType>
{
private int maxSize;
private CircularFifoBuffer storageArea;
public LimitedSizeQueue(final int maxSize)
{
if (maxSize > 0)
{
this.maxSize = maxSize;
storateArea = new CircularFifoBuffer(maxSize);
}
else
{
throw new IllegalArgumentException("blah blah blah");
}
}
... implement the Queue interface using the CircularFifoBuffer class
}
The only thing I know that has limited space is the BlockingQueue interface (which is e.g. implemented by the ArrayBlockingQueue class) - but they do not remove the first element if filled, but instead block the put operation until space is free (removed by other thread).
To my knowledge your trivial implementation is the easiest way to get such an behaviour.
You can use a MinMaxPriorityQueue from Google Guava, from the javadoc:
A min-max priority queue can be configured with a maximum size. If so, each time the size of the queue exceeds that value, the queue automatically removes its greatest element according to its comparator (which might be the element that was just added). This is different from conventional bounded queues, which either block or reject new elements when full.
An LRUMap is another possibility, also from Apache Commons.
http://commons.apache.org/collections/apidocs/org/apache/commons/collections/map/LRUMap.html
Ok I'll share this option. This is a pretty performant option - it uses an array internally - and reuses entries. It's thread safe - and you can retrieve the contents as a List.
static class FixedSizeCircularReference<T> {
T[] entries
FixedSizeCircularReference(int size) {
this.entries = new Object[size] as T[]
this.size = size
}
int cur = 0
int size
synchronized void add(T entry) {
entries[cur++] = entry
if (cur >= size) {
cur = 0
}
}
List<T> asList() {
int c = cur
int s = size
T[] e = entries.collect() as T[]
List<T> list = new ArrayList<>()
int oldest = (c == s - 1) ? 0 : c
for (int i = 0; i < e.length; i++) {
def entry = e[oldest + i < s ? oldest + i : oldest + i - s]
if (entry) list.add(entry)
}
return list
}
}
public class ArrayLimitedQueue<E> extends ArrayDeque<E> {
private int limit;
public ArrayLimitedQueue(int limit) {
super(limit + 1);
this.limit = limit;
}
#Override
public boolean add(E o) {
boolean added = super.add(o);
while (added && size() > limit) {
super.remove();
}
return added;
}
#Override
public void addLast(E e) {
super.addLast(e);
while (size() > limit) {
super.removeLast();
}
}
#Override
public boolean offerLast(E e) {
boolean added = super.offerLast(e);
while (added && size() > limit) {
super.pollLast();
}
return added;
}
}