How to populate help combo box
class MyFrame : public CFrameWnd {
...
CMFCMenuBar m_menuBar;
...
};
int MyFrame::OnCreate(LPCREATESTRUCT lpCreateStruct )
{
int res = CFrameWnd::OnCreate(lpCreateStruct);
m_menuBar.Create(this);
m_menuBar.EnableHelpCombobox(1, _T("Test"), 150 );
m_menuBar.CreateFromMenu(hMenu,FALSE,TRUE);
CMFCToolBarComboBoxButton* combo = m_menuBar.GetHelpCombobox();
combo->AddItem("Item 1");
combo->AddItem("Item 2");
combo->AddItem("Item 3");
combo->AddItem("Item 4");
combo->EnableWindow(true);
combo->SelectItem(2,FALSE);
combo->SetCenterVert();
combo->SetDropDownHeight(150);
return res;
}
The item text "Item 3" which was selected is shown combo field but nothing happnes when I hit the button on dropdown. CMFCToolBarComboBoxButton::AddItem(...) returns valid index and CMFCToolBarComboBoxButton::Count(...) returns 4 as expected.
Related
I have ribbon button with a set of sub-items added. Such items are displayed when the user clicks on the tiny arrow below the button. I'd like to display such dropdown-menu when the button itself is clicked. How can I do that?
My initial idea was to programmatically show the menu when the user clicks the button. I've been able to do the same on toolbars (here) but using a similar solution on ribbons creates an infinite recursion:
// ...
ON_COMMAND(ID_RIBBON_BUTTON, &MainFrame::OnButtonClicked)
// ...
CMFCRibbonPanel *panel = /* initialization */
CMFCRibbonButton *button = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Caption");
panel->Add(button);
CMFCRibbonButton *item1 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 1");
button->AddSubItem(item1);
CMFCRibbonButton *item2 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 2");
button->AddSubItem(item2);
// ...
void MainFrame::OnButtonClicked()
{
if (auto button = static_cast<CMFCRibbonButton *>(m_ribbons.wndRibbonBar.FindByID(ID_RIBBON_BUTTON))) {
// button->OnClick({}); // <- causes infinite recursion
// What to do here?
}
}
The easiest way I've found so far is to use the protected method CMFCRibbonButton::OnShowPopupMenu. It implies deriving the CMFCRibbonButton class and changing the visibility of the method:
#include <afxribbonbutton.h>
class CMyMFCRibbonButton : public CMFCRibbonButton {
public:
using CMFCRibbonButton::CMFCRibbonButton;
virtual void OnShowPopupMenu() override {
CMFCRibbonButton::OnShowPopupMenu();
}
};
// ...
ON_COMMAND(ID_RIBBON_BUTTON, &MainFrame::OnButtonClicked)
// ...
CMFCRibbonPanel *panel = /* initialization */
CMyMFCRibbonButton *button = new CMyMFCRibbonButton(ID_RIBBON_BUTTON, "Caption");
panel->Add(button);
CMFCRibbonButton *item1 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 1");
button->AddSubItem(item1);
CMFCRibbonButton *item2 = new CMFCRibbonButton(ID_RIBBON_BUTTON, "Item 2");
button->AddSubItem(item2);
// ...
void MainFrame::OnButtonClicked()
{
if (auto button = static_cast<CMyMFCRibbonButton*>(m_ribbons.wndRibbonBar.FindByID(ID_RIBBON_BUTTON))) {
button->OnShowPopupMenu();
}
}
I am trying to extend the qt filesystembrowser example (Qt-Creator -> Welcome -> Examples -> filesystembrowser). I added a button to main.qml
Button {
id: button
x: 28
y: 12
text: qsTr("rootPath")
onClicked: {
view.model.setRoot("/home/myusername/test/")
view.update()
}
}
which should change the root directory. For this, I also added the following function
Q_INVOKABLE QModelIndex setRoot(QString newPath) {
qInfo() <<"root path "<< this->rootPath();
newPath.replace(0,7,"");
setRootPath(newPath);
}
After hitting the button twice, qInfo tells me that the root path is now /home/myusername/test/ but the view is not updated. What am I missing here?
The problem is that the rootIndex of the TreeView does not change because it does not update the view.
One solution is to create a rootIndex property that returns the index that is placed in the TreeView, this must be changed when a new path is established, for it is going to overwrite the setRootPath method and eliminate the rootPathIndex property that was sent through setContextProperty():
main.cpp
...
class DisplayFileSystemModel : public QFileSystemModel {
Q_OBJECT
Q_PROPERTY(QModelIndex rootIndex READ rootIndex WRITE setRootIndex NOTIFY rootIndexChanged)
public:
...
Q_INVOKABLE QModelIndex setRootPath(const QString &newPath){
QModelIndex ix = QFileSystemModel::setRootPath(newPath);
setRootIndex(ix);
return ix;
}
QModelIndex rootIndex() const{
return mRootIndex;
}
void setRootIndex(const QModelIndex &rootIndex){
if(mRootIndex == rootIndex)
return;
mRootIndex = rootIndex;
Q_EMIT rootIndexChanged();
}
Q_SIGNAL void rootIndexChanged();
private:
QModelIndex mRootIndex;
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQmlApplicationEngine engine;
qmlRegisterUncreatableType<DisplayFileSystemModel>("io.qt.examples.quick.controls.filesystembrowser", 1, 0,
"FileSystemModel", "Cannot create a FileSystemModel instance.");
DisplayFileSystemModel *fsm = new DisplayFileSystemModel(&engine); // change
fsm->setRootPath(QDir::homePath());
fsm->setResolveSymlinks(true);
engine.rootContext()->setContextProperty("fileSystemModel", fsm);
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
main.qml
...
Row {
...
Repeater {
model: [ "rootPath", "None", "Single", "Extended", "Multi", "Contig."]
Button {
text: modelData
exclusiveGroup: eg
checkable: modelData != "rootPath"
checked: index === 1
onClicked: {
if(modelData != "rootPath")
view.selectionMode = index
else{
view.model.setRootPath("/home/myusername/test/")
}
}
}
}
}
...
TreeView {
id: view
anchors.fill: parent
anchors.margins: 2 * 12 + row.height
model: fileSystemModel
rootIndex: fileSystemModel.rootIndex //change
selection: sel
...
The complete example can be found in the following link.
C++ Builder XE8
if i select Num 1 Memo will show Test
if i select other items memo will show Else Test
void __fastcall TForm1::FormCreate(TObject *Sender)
{
ListBox1->Items->Add("Num 1");
ListBox1->Items->Add("Num 2");
ListBox1->Items->Add("Num 3");
auto str = listBox1->SelectedItem->ToString();
if (str == L"Num 1") {
Memo1->Text = "Test";
}
else {
Memo1->Text = "Else Test";
}
}
The Form's OnCreate event (which you SHOULD NOT be using in C++, use the Form's constructor instead) is too soon to detect the user's selection, as the user has not had a chance to see the UI yet to select anything. Use the ListBox's OnChange event instead.
Also, TListBox does not have a SelectedItem property. In FireMonkey (which I assume you are using instead of VCL), it has a Selected property instead.
Try this:
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
ListBox1->BeginUpdate();
try {
ListBox1->Items->Add("Num 1");
ListBox1->Items->Add("Num 2");
ListBox1->Items->Add("Num 3");
}
__finally {
ListBox1->EndUpdate();
}
}
void __fastcall TForm1::ListBox1Change(TObject *Sender)
{
TListBoxItem *Item = ListBox1->Selected;
if (Item) {
String str = ListBox1->Selected->Text;
if (str == L"Num 1") {
Memo1->Text = "Test";
}
else {
Memo1->Text = "Else Test";
}
}
else {
Memo1->Text = "Nothing";
}
}
I want to be able to show ToolTips for QMenu items (QActions). The best I have achieved is to connect the hovered signal of the QAction to a QTooltip show:
connect(action, &QAction::hovered, [=]{
QToolTip::showText(QCursor::pos(), text, this);
});
The problem is that sometimes the program will position the tooltip below the menu, specially when changing menus.
Is there any way to force the tooltip to show on top?
Since Qt 5.1, you can use QMenu's property toolTipsVisible, which is by default set to false.
See the related Qt suggestion.
You can subclass QMenu and reimplementing QMenu::event() to intercept the QEvent::ToolTip event and call QToolTip::showText to set the tooltip for the active action :
#include <QtGui>
class Menu : public QMenu
{
Q_OBJECT
public:
Menu(){}
bool event (QEvent * e)
{
const QHelpEvent *helpEvent = static_cast <QHelpEvent *>(e);
if (helpEvent->type() == QEvent::ToolTip && activeAction() != 0)
{
QToolTip::showText(helpEvent->globalPos(), activeAction()->toolTip());
} else
{
QToolTip::hideText();
}
return QMenu::event(e);
}
};
Now you can use your custom menu like :
Menu *menu = new Menu();
menu->setTitle("Test menu");
menuBar()->addMenu(menu);
QAction *action1 = menu->addAction("First");
action1->setToolTip("First action");
QAction *action2 = menu->addAction("Second");
action2->setToolTip("Second action");
I was wondering if there was a way to set a custom Authors category in a Gtk::AboutDialog class via gtkmm. I know there are the following methods:
set_artists()
set_authors()
set_documenters()
set_translator_credits()
But I wanted to add a custom category. Right now I have a program that accepts a bunch of plugins, so on startup when it scans for plugins I would like to populate a "Plugins" page on the about screen once you click credits that shows all of the plugin authors' names (removing duplicates of course). The logic is already there, but it looks quite odd adding them to the artists or documenters categories where they certainly do not belong.
Is there an easy way to add a new category besides rolling my own?
Nice question! In GTK 3, this is fairly easy. You have to do some manipulation of the About dialog's internal children, which may change in future releases, so be warned!
I've written a quick-n-dirty example in Vala that does what you want. That was faster for me because I almost never use Gtkmm. It shouldn't be too hard to translate though.
using Gtk;
int main(string[] args)
{
Gtk.init(ref args);
var dialog = new AboutDialog();
// Fetch internal children, using trickery
var box = dialog.get_child() as Box;
Box? box2 = null;
ButtonBox? buttons = null;
Notebook? notebook = null;
box.forall( (child) => {
if(child.name == "GtkBox")
box2 = child as Box;
else if(child.name == "GtkButtonBox")
buttons = child as ButtonBox;
});
box2.forall( (child) => {
if(child.name == "GtkNotebook")
notebook = child as Notebook;
});
// Add a new page to the notebook (put whatever widgets you want in it)
var plugin_page_index = notebook.append_page(new Label("Plugin 1\nPlugin 2"),
new Label("Plugins"));
// Add a button that toggles whether the page is visible
var button = new ToggleButton.with_label("Plugins");
button.clicked.connect( (button) => {
notebook.page = (button as ToggleButton).active? plugin_page_index : 0;
});
buttons.pack_start(button);
buttons.set_child_secondary(button, true);
// Set some other parameters
dialog.program_name = "Test Program";
dialog.logo_icon_name = Gtk.Stock.ABOUT;
dialog.version = "0.1";
dialog.authors = { "Author 1", "Author 2" };
dialog.show_all(); // otherwise the new widgets are invisible
dialog.run();
return 0;
}
In GTK 2, this is much more difficult, although probably not impossible. You have to connect to the Credits button's clicked signal, with a handler that runs after the normal handler, and then get a list of toplevel windows and look for the new window that opens. Then you can add another page to that window's GtkNotebook.
I would suggest doing it a little differently: add a Plugins button to the action area which opens its own window. Then you don't have to go messing around with internal children. Here's another Vala sample:
using Gtk;
class PluginsAboutDialog : AboutDialog {
private Dialog _plugins_window;
private Widget _plugins_widget;
public Widget plugins_widget { get {
return _plugins_widget;
}
set {
var content_area = _plugins_window.get_content_area() as VBox;
if(_plugins_widget != null)
content_area.remove(_plugins_widget);
_plugins_widget = value;
content_area.pack_start(value);
}}
public PluginsAboutDialog() {
_plugins_window = new Dialog();
_plugins_window.title = "Plugins";
_plugins_window.add_buttons(Stock.CLOSE, ResponseType.CLOSE, null);
_plugins_window.response.connect((widget, response) => { widget.hide(); });
var buttons = get_action_area() as HButtonBox;
// Add a button that opens a plugins window
var button = new Button.with_label("Plugins");
button.clicked.connect( (button) => {
_plugins_window.show_all();
_plugins_window.run();
});
button.show();
buttons.pack_start(button);
buttons.set_child_secondary(button, true);
}
public static int main(string[] args) {
Gtk.init(ref args);
var dialog = new PluginsAboutDialog();
// Make a widget for the plugins window
var can_be_any_widget = new Label("Plugin 1\nPlugin 2");
dialog.plugins_widget = can_be_any_widget;
// Set some other parameters
dialog.program_name = "Test Program";
dialog.logo_icon_name = Gtk.Stock.ABOUT;
dialog.version = "0.1";
dialog.authors = { "Author 1", "Author 2" };
dialog.run();
return 0;
}
}