Macros to Simplify Redundant Q_PROPERTY() Hell

When you need to expose C++ object for accessing in QML, you may have to write a lot of annoying and trivial Q_PROPERTY()s, getters, setter slots, signals, and private member variables. They will makes your class a mess (any mostly are duplicated). For example, a QString myFoo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyObjectExposedToQml : public QObject
{
Q_OBJECT
Q_PROPERTY(QString myFoo READ myFoo WRITE setMyFoo NOTIFY myFooChanged)
public:
QString myFoo() const { return m_myFoo ; }
public slots:
void setMyFoo(QString myFoo) {
if (m_myFoo == myFoo) { return; }
m_myFoo = myFoo;
emit myFooChanged(myFoo);
}
signals:
void myFooChanged(QString myFoo);
private:
QString m_myFoo;
}

Though only one property here but has been nearly create a getter/setter/signal/variable hell. So make some macros to get rid of these shit:

Read More

QML Controls 1.x ComboBox.onWheel Event & Flickable

If you place a ComboBox on a Flickable, you may unhappily notice that ComboBox steals your mouse wheel events on Flickable.

I think an UI component like ComboBox which accepts mouse wheel event is totally a stupid idea and a great anti-pattern of UI/UX (the value of ComboBox is quite easily to be accidently modified). However, the API of QtQuick Controls, no matter 1 or 2, are totally moron. They totally don’t provide any API to deal with a lot of shit. So you have to workaround it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// MyComboBox.qml
import QtQuick 2.6
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls.Private 1.0

ComboBox {
id: root
property Item _flickableItem
Component.onCompleted: {
var p = root
while (!p.flick) { // no .flick()
//console.log(p.toString(), p.flick)
p = p.parent
if (!p) {return}
}
//console.log(">>", p.toString(), p.flick)
root._flickableItem = p
}
...
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onPressed: mouse.accepted = false
onReleased: mouse.accepted = false
onClicked: mouse.accepted = false
onDoubleClicked: mouse.accepted = false;
onPressAndHold: mouse.accepted = false;
onWheel: {
if (root._flickableItem) {
root._flickableItem.flick(0, wheel.angleDelta.y * 5)
}
}
}
}

Explanation

  1. When component is loaded and instantialized (Component.onCompleted), use a while loop find any parent component has flick attribute. If found, assign _flickableItem property as it.
  2. Place a MouseArea to “steal the wheels events back”, which invoke _flickableItem.flick() when onWheel.

One-By-One Promise

Let’s define a function to simulate calling API via Promise and setTimeout():

1
2
3
4
5
6
7
var callAPI = (api, arg) => new Promise((resolve, reject)=>{ // <- callAPI() always return this promise
setTimeout(()=> {
let msg = `API "${api}" called successfully! ==> ${JSON.stringify(arg)}`
console.log(msg)
resolve(msg) // You can get msg via then(): callAPI(...).then((msg)=>{ ... })
}, Math.floor(Math.random()*1000)) // Simulate unstable network & server latency
})

Use like this:

1
2
3
callAPI("AddUser", { username: "ib", password: "ib" }).then((x)=>{
console.log("API test!")
})

Result

1
2
API "AddUser" called successfully! ==> {"username":"ib","password":"ib"}
API test!

Call Multiple APIs Simultaneously

When you have to call a lot of asynchronous APIs simultaneously, you may use Promise.all() like this::

Read More

第二十四年

原本這個週末打算來寫 code 的但完全沒心情。人生的第二十四個年頭,給自己留下一點想法紀錄,給未來的自己看看:自己成長了嗎?

這篇紀錄了我目前為止的一部分關於這個世界的想法,內容估計會得罪非常多人。如果你我有緣,看到了這篇文章,且有什麼想法得罪到你,開罵前懇請先冷靜下來,願意的話我們可以討論,畢竟很有可能邏輯錯誤的人其實是我而不是你。

我很尊敬的程式設計師唐鳳很常講的、很注重的一點:溝通。我期望自己總有一天能夠有那種邏輯與耐心與脾氣。

Read More