I have a graphics view which contains a scene with some graphics items. How can I make those graphics items appear on the left side of the scene and not in the center ?
I have looked through many ideas but no luck.
The easiest way is to add an invisible QGraphicsRectItem as the first item.
Then add other items as children of that first item.
The center of the first item is the center of the coordination.
QGraphicsScene *scene = new QGraphicsScene(widget.graphicsView);
// ....
QGraphicsRectItem *frame = scene->addRect(-100,-100,100,100);
frame->setPen(Qt::NoPen);
// ....
// Add new items as children of frame
// Align them relative to their parent
^
|
|
-100,100 | 100,100
+-----------------------------+
| | |
| | |
| | |
| | |
| | |
| | |
| | |
---------------------------+------------------------>
| | |
| | |
| | |
| | |
| | |
| | |
| | |
+-----------------------------+
-100,100 | 100,-100
|
To make it aware to window size, override these methods:
class MainForm : public QMainWindow
{
//...
QGraphicsScene *scene; // Move it here
QGraphicsRectItem *frame; // Move it here
protected:
virtual void resizeEvent(QResizeEvent * event);
virtual bool event(QEvent * event);
virtual void resizeAction();
//...
};
void MainForm::resizeAction()
{
QRectF rect(field->rect());
widget.graphicsView->setSceneRect(rect);
widget.graphicsView->fitInView(rect, Qt::KeepAspectRatio);
}
void MainForm::resizeEvent(QResizeEvent * event)
{
resizeAction();
QMainWindow::resizeEvent(event);
}
bool MainForm::event(QEvent * event)
{
if (event->type() == QEvent::Show)
resizeAction();
return QMainWindow::event(event);
}
Scene_item.setSceneRect(x0,y0,x1,y1);
Related
How to make a widget via GTK that looks like the following?
------------------
| Text1: | 1 |
|-----------+----|
| Text2: | 10 |
|-----------+----|
| | |
| | |
| | |
------------------
'Text1', 'Text2' - constant strings; '1', '10' - dynamically changed values.
What Gtk::Widget's should I use for that?
Make Gtk::Grid with labels, align them, set column spacing and column homogeneous.
#include <gtkmm.h>
class window : public Gtk::Window {
protected:
Gtk::Box box;
Gtk::Grid grid;
Gtk::Button button;
Gtk::Label name1, name2, value1, value2;
int n_click = 0;
public:
window();
~window() = default;
void on_click() {
value1.set_label("1");
value2.set_label(n_click % 2 ? "1" : "10");
n_click++;
queue_draw();
}
};
window::window() : button("Update"),
name1("Text:"),
name2("Text2:")
{
add(box);
box.pack_start(button);
button.signal_clicked().connect(sigc::mem_fun(*this, &window::on_click));
box.pack_end(grid, Gtk::PACK_SHRINK);
grid.attach(name1, 0, 0, 2, 1);
grid.attach(value1, 2, 0, 1, 1);
grid.attach(name2, 0, 1, 2, 1);
grid.attach(value2, 2, 1, 1, 1);
name1.set_halign(Gtk::ALIGN_START);
name2.set_halign(Gtk::ALIGN_START);
value1.set_halign(Gtk::ALIGN_START);
value2.set_halign(Gtk::ALIGN_START);
grid.set_column_spacing(10);
grid.set_column_homogeneous(true);
show_all();
}
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create(argc, argv, "");
window win;
return app->run(win);
}
From this post, I have set up the code by putting in the OnInitDialog event:
LITEM* pItem = new LITEM;
pItem->iLink = 0; // Url index is 0
//LIF_ITEMINDEX is required for iLink, LIF_STATE is required for modifing state
pItem->mask = LIF_ITEMINDEX | LIF_STATE;
//using LIS_DEFAULTCOLORS state
pItem->state = LIS_ENABLED | LIS_FOCUSED | LIS_DEFAULTCOLORS;
pItem->stateMask = LIS_ENABLED | LIS_FOCUSED | LIS_DEFAULTCOLORS;
// Send the LM_SETITEM MESSAGE with pItem
HWND m_hWnd=nil; GetDlgItem(IDC_lbstackoverflow, &m_hWnd);
And from OnCtrlColor event:
pDC->SetTextColor(RGB(255, 0, 0));
pDC->SetBkColor(normal);
pDC->SetDCBrushColor(RGB(255, 255, 255));
return (HBRUSH)GetStockObject(DC_BRUSH);
After the code runs, my result is:
If I click on it, now it works:
But, how I can change text color?
You may not be setting the control state correctly.
Please try the MFC way (it works for me). Add to your dialog class:
CLinkCtrl syslink;
Connect it to the resource ID of your link:
void CMFCApplication4Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_SYSLINK1, syslink);
}
and in OnInitDialog add this:
syslink.SetItemState(0, LIS_ENABLED | LIS_FOCUSED | LIS_DEFAULTCOLORS,
LIS_ENABLED | LIS_FOCUSED | LIS_DEFAULTCOLORS);
I see red link with your code in OnCtlColor.
I have created CListCtrl using LVS_REPORT and LVS_OWNERDRAWFIXED style. But DrawItem() and MeasureItem() not get called.
CAlarmList *pAlrmList;
pAlrmList= new CAlarmList; //CAlarmList derived from CLIstCtrl
pAlrmList->Create(WS_CHILD | WS_VISIBLE | WS_VSCROLL| LVS_OWNERDRAWFIXED| LVS_REPORT | LVS_EX_FULLROWSELECT , CRect(0,0,600,400), this, ID_ALARMLIST);
void CAlarmList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
lpMeasureItemStruct->itemHeight = 22;
}
void CAlarmList::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
int iListItem = lpDIS->itemID;
}
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
Small picture to depict what the problem is:
external_widget
+--------------------------------------------------+
| |
| |
| layout_widget |
| +-------------------------------+ |
| | | |
| | [internal_layout] | |
| | | |
| | | |
| | [Some Another Widget] | |
| +-------------------------------+ |
| |
+--------------------------------------------------+
layout_widget - just QWidget with vertical layout. It contains another internal_layout and another widgets.
internal_layout - layout where the widgets will be added and deleted in future.
external_widget - just QWidget with no layout, I control the position and size of layout widget and other widgets manually.
When I add some widgets in internal_layout - it sends LayoutRequest event (as far as I know, I saw this in Qt source codes). This event is catched by parent widget and parent widget tells his layout that something is changed which forces layout to recalculate layout_widget sizeHint() etc.
Do I understand this process right?
The problem is that sizeHint() is changed, but my external_widget doesn't know anything about that. I want to get notification about layout_widget sizeHint() changes. Is it possible?
I even tried to do this:
external widget ctor:
{
layout_widget->installEventFilter(this);
}
and tried to catch them:
void ...eventFilter(QObject* obj, QEvent* event )
{
if (obj == layout_widget && event == QEvent::LayoutRequest)
{
// TODO;
}
}
and I never got into "TODO" block.
Do layout_widget send some events or notifications that something was changed inside him and it should be resized, i.e. his sizeHint() has been changed?
Suppose I have a splitter with 2 rows.
--------
| |
--------
| |
--------
How do I make it to this
---------
| | |
| | |
| | |
---------
switch from horizontal split to vertical split
without having to re-create the whole splitter?
Code is:
if (!m_wndSplitter.CreateStatic(this, 1, 2, WS_CHILD|WS_VISIBLE))
{
TRACE0("Failed to create splitter window\n");
return FALSE;
}
if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CWnd), CSize(200, 100), NULL))
{
TRACE0("Failed to create CView1\n");
return FALSE;
}
if (!m_wndSplitter.CreateView(0, 2, RUNTIME_CLASS(CWnd), CSize(500, 100), NULL))
{
TRACE0("Failed to create CView2\n");
return FALSE;
}
Don't use CreateStatic, just use Create on the splitter. Then you have a so called dynamic splitter, see more here.
When converting the splitter from horz to vert, you have to remove the views from the splitter and attach them again afterwards. You have to do this in your document-class. I can post a method to do this if needed.
Ok, here is a method to switch views in a pane:
CView* CGMBefundDoc::SwitchToView(CView* pNewView,int row,int col)
{
CMainFrame* pMainWnd = (CMainFrame*)AfxGetMainWnd();
CSplitterWnd* pSplitter = &pMainWnd->m_wndSplitter;
CView* pOldActiveView = reinterpret_cast<CView*>(pSplitter->GetPane(row,col));
ASSERT(pOldActiveView != pNewView);
// set flag so that document will not be deleted when view is destroyed
m_bAutoDelete = FALSE;
// Dettach existing view
RemoveView(pOldActiveView);
// set flag back to default
m_bAutoDelete = TRUE;
// Set the child window ID of the active view to the ID of the corresponding
// pane. Set the child ID of the previously active view to some other ID.
::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, 0);
::SetWindowLong(pNewView->m_hWnd,GWL_ID,pSplitter->IdFromRowCol(row,col));
// Show the newly active view and hide the inactive view.
pNewView->ShowWindow(SW_SHOW);
pOldActiveView->ShowWindow(SW_HIDE);
// Attach new view
AddView(pNewView);
// Set active
pSplitter->GetParentFrame()->SetActiveView(pNewView);
pSplitter->RecalcLayout();
return pOldActiveView;
}
I hope you get the idea, otherwise just ask.
-----------|----------|
| | |
| | |
| |----------|
| | |
| | |
-----------|----------|
2 column splitter with right side having 2 rows, one Up and one Down and another one with left side to the Up and Down ?