2015-10-09 29 views
2

在Qt中,您可以使用Qt Designer或使用C++來定義Tab鍵順序。小部件之間的關係是相互關聯的,所以沒有索引或其他東西。我現在想要的是「打破」小部件的循環鏈,以便獲得鏈條的開始和結束。如何打破Qt中的小部件選項卡順序鏈?

的圓形標籤順序將是:

A - B 
| | 
D - C 

欲(註釋缺失A和d之間的鏈路):

A - B 
    | 
D - C 

這更像一個線,而不是一個循環:

A - B - C - D 

所以用戶「停在」一端,必須回去使用另一個方向。


更新:我有另一個想法了。如果我重新實現什麼:

bool QWidget::focusNextPrevChild(bool next) 

按照documentation一個可以用它來實現自定義的焦點行爲。

以我動態場景,其中在GUI按鈕在運行時被調整,我將不得不超負荷的功能和集,例如,一個內部標誌allowFocusNextallowFocusPrev然後忽略如果必要的聚焦請求。當我嘗試過時,我會在這裏報告。同時歡迎任何評論!? :-)

+0

你試過'QWidget :: setTabOrder(D,D)'? –

+0

補充:http://doc.qt.io/qt-5/qwidget.html#setTabOrder – ManuelH

+0

@king_nak:這似乎是一個好主意。我報告,如果它的工作結束:-) – FrozenTarzan

回答

2

我找到了一個解決方案,但它有點哈克。該QWidget::setTabOrder將不允許鏈上的小部件本身,所以這種方法也無濟於事(即使你使用的焦點代理)

但是,您可以定義一個「焦點轉發」:

class FocusForwarder : public QWidget 
{ 
public: 
    explicit FocusForwarder(QWidget *proxy) : 
     QWidget((QWidget *) proxy->parent()), 
     m_proxy(proxy) 
    { 
     setFocusPolicy(Qt::TabFocus); 
    } 
protected: 
    void focusInEvent(QFocusEvent *) { 
     m_proxy->setFocus(); 
    } 
private: 
    QWidget *m_proxy; 
}; 

而在開始和你末尾添加它們鏈條:

FocusForwarder *w1 = new FocusForwarder(ui->bA); 
FocusForwarder *w2 = new FocusForwarder(ui->bD); 

QWidget::setTabOrder(w1, ui->bA); 
QWidget::setTabOrder(ui->bA, ui->bB); 
QWidget::setTabOrder(ui->bB, ui->bC); 
QWidget::setTabOrder(ui->bC, ui->bD); 
QWidget::setTabOrder(ui->bD, w2); 

詳細

對於setTabOrder工作,小部件必須在同一窗口。爲了確保這一點,轉發器被放置在代理的父代(在初始化程序列表中)。

對於這種機制,焦點方向(Tab或Shit + Tab)無關緊要。只要FocusFowarder獲得焦點,它就會「轉發」它的代理。 方向由Qt在內部處理。你只需在你的連鎖店中添加「哨兵」。

使用在QtDesigner

當你想在QtDesigner使用它,你會創建一個Widget,並促進它的轉發器。正如你不能直接設置代理,你可以添加一個動態屬性爲代理的名稱,就像這樣:

class FocusForwarderDesigner : public QWidget 
{ 
    Q_OBJECT 
    Q_PROPERTY(QString proxyName READ proxyName WRITE setProxyName) 
public: 
    QString proxyName() { 
     return (m_proxy) ? m_proxy->objectName() : QString::null; 
    } 
    void setProxyName(QString name) { 
     m_proxy = parent()->findChild<QWidget *>(name); 
    } 

    explicit FocusForwarderDesigner(QWidget *parent = NULL) : 
     QWidget(parent) {} 

protected: 
    void focusInEvent(QFocusEvent *) { 
     if (m_proxy) m_proxy->setFocus(); 
    } 
private: 
    QWidget *m_proxy; 
} 

在設計中,可以添加一個字符串屬性名稱爲proxyName並將其設置爲代理服務器的名稱。不要忘記在設計器中將focus policy設置爲Tab Focus

+0

我已經嘗試過你的方法,它適用於小部件創建一次的靜態情況。在使用hide()和show()來更改UI外觀的動態情況下,FocusForwarder僅在其目標可見時才起作用。我猜Qt在隱藏小部件時會在內部改變焦點鏈。所以當最後一個小部件(指向結束焦點轉發器)被隱藏時,Qt將它的「下一個焦點」重定向到第一個小部件,因此它再次循環。我認爲必須有一種將通告改爲線性行爲的Qt方法:-( – FrozenTarzan

0

經過一些額外的想法後,我發佈了一個我自己的問題的答案,因爲它是一個工作解決方案,但它並不理想。因此,我仍在尋找更好的!作爲說明,我的應用程序主要依靠鼠標滾輪交互來改變小部件的焦點。

在我的問題我提到了首要的:

bool focusNextPrevChild(bool next) 

可能導致一個工作系統。如果「接收」小部件被標記爲「最後一項」或「第一項」並且「下一個」參數導致循環行爲,則其將簡單地忽略焦點。雖然這適用於製表符和空格+製表符組合鍵,但有些情況下不會顯式調用focusNextPrevChild。在我的情況下,它不會被稱爲與鼠標滾輪事件相關的焦點更改。

我做的卻是壓倒:

void wheelEvent(QWheelEvent* event) 

這讓我對所有相關的鼠標滾輪的焦點事件的直接控制。我重寫功能如下:

void SelectionIconButton::wheelEvent(QWheelEvent* event) 
{ 
    bool next = event->delta() > 0; 

    if (m_IsLastInFocusChain && next) { 
     event->accept(); 
     return; 
    } 

    if (m_IsFirstInFocusChain && !next) { 
     event->accept(); 
     return; 
    } 

    QPushButton::wheelEvent(event); 
} 

所以這個系統的要求是:

  • 每個部件有以某種方式實現兩個布爾變量和處理他們的 狀態。
  • 每個這些部件的有或在啓動 或在動態畫面上appliation使用
  • ,只監聽 期間配置wheelEvent不允許我來處理tab鍵和空格+ Tab鍵 組合

您會看到此解決方案有效,但需要將其應用於大型應用程序。我正在考慮更通用的解決方案。也許一個全局列表在屏幕更改時更新。這個全球名單然後會以某種方式決定是否允許焦點改變。不幸的是,鼠標滾輪事件再次出現問題,因爲一些小部件是「活動的」,輪子事件甚至不想改變焦點,而是改變輸入字段中的值,例如。

編輯: 我可能要補充一點的QWidget::wheelEvent()QPushButton::wheelEvent()默認的實現,還有更多Qt的窗口小部件忽略通過設置event->ignore()事件。 在我的應用程序中,所有這些被忽略的事件都會被捕獲到一個高級別小部件,然後它將解釋QWheelEvent並使用其delta來調用focusPreNextChild()適當的時間。

相關問題