MFC: Displaying a tabulated display of text items - mfc

This should be simple it seems but I can't quite get it to work. I want a control (I guess CListBox or CListCtrl) which displays text strings in a nice tabulated way.
As items are added, they should be added along a row until that row is full, and then start a new row. Like typing in your wordprocessor - when the line is full, items start being added to the next line, and the control can scroll vertically.
What I get when trying with a list-mode CListCtrl is a single row which just keeps growing, with a horizontal scroll bar. I can't see a way to change that, there must be one?

You probably need a list control wth LVS_REPORT. If you expect the user to add items interactively using a keyboard, you probably need a data grid, not a list. Adding editing to list control subitems is not easy, and it would be easier to start from CWnd. Search "MFC Data Grid" to find some open source class libraries that implemented the feature.
If you can afford adding /clr to your program, you can try the data grid classes in Windows Forms using MFC's Windows Form hosting support. You will find a lot more programming resources on data grid classes in Windows Forms than any other third-party MFC data grid class library.

If you use CRichEditCtrl you can set it to word-wrap, take a look at this snippet extracted from:
http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.ui/2004-03/0111.html
(I've derived my own QRichEditCtrl from the MFC CRichEditCtrl,
and here's the relevant code:)
void QRichEditCtrl::SetWordWrap(bool bWrap)
{
RECT r;
GetWindowRect(&r);
CDC * pDC = GetDC();
long lLineWidth = 9999999; // This is the non-wrap width
if (bWrap)
{
lLineWidth = ::MulDiv(pDC->GetDeviceCaps(PHYSICALWIDTH),
1440, pDC->GetDeviceCaps(LOGPIXELSX));
}
SetTargetDevice(*GetDC(), lLineWidth);
}

Related

Reordering MFC control IDs automatically

I've got a pretty old MFC application that's been touched by many people over the years (most of them probably not even CS guys) and it follows, what I like to call the "anarchy design pattern."
Anyway, one of the dialogs has a series of 56 vertical sliders and check boxes. However, there are additional sliders and checkboxes on the dialog as shown below.
Now, the problem is that the additional sliders and checkboxes take on IDs that are in sequence with the slider/checkbox series of the dialog. My task is to add more sliders and checkboxes to the series (in the blank space in the Slider Control group box) Unfortunately, since IDC_SLIDER57 through IDC_SLIDER61 are already in the dialog (same goes for the checkboxes), existing code, such as the snippet below will break:
pVSlider = (CSliderCtrl *)GetDlgItem(IDC_SLIDER1+i);
Is there a better way to modify the resource file without doing it manually? I've seen a third party tool called ResOrg that looks like it'll help do what I want, but the software is a bit pricey, especially since I'll only use it once. I guess I can give the demo a try, but the limitations might restrict me.
FYI, I'm using Visual C++ 6.0 (yes...I know, don't laugh, it's being forced upon me).
Instead of writing:
pVSlider = (CSliderCtrl *)GetDlgItem(IDC_SLIDER1+i);
you could write:
pVSlider = (CSliderCtrl *)GetDlgItem(GetSliderID(i));
where GetSlider is a function that returns the id of slider number i.
GetSlider function
int GetSliderID(int nslider)
{
static int sliderids[] = {IDC_SLIDER1, IDC_SLIDER2, IDC_SLIDER3, .... IDC_SLIDERn};
ASSERT(nslider < _countof(sliderids));
return sliderids[nslider];
}
With this method the IDC_SLIDERn symbols dont need to have sequential values.

QT QIcon properties for custom widget in designer

I have been working for a little while now on creating a QT custom designer widget for GUI menus. The idea being that you simply drag it into the designer, select the number of frames you'd like, how many buttons per frame, etc. and it generates and sizes everything for you.
The way the widget is structured there are properties to configure each button for the frame you are in. For example, you would use the button0Text field to enter text under Button0 while editing in frame 0, then use it again to edit Button0 which is in frame 1. Both buttons would retain the individual changes for each frame.
The Problem
Normally when I switch frames all of my properties are updated to reflect the status of the frame. The exception being QIcon. The correct icon is retained in the actual graphical representation and builds correctly, however the file path in the property list is always of the last edited for that property. I think this will be extremely confusing to an end user and I have found no way to fix it. So for example, if I set text and icons in frame 0 then switch to frame 1 the text in the property list will update to reflect the state of frame 1 but the icon path names will still show my last edit in frame 0 and not the actual icon in frame 1.
I have tried things as simple as:
setProperty("button0Icon", getButton0Icon());
That code works on properties like text, but not for the icon. I try executing it immediately after changing frames.
I have also tried:
#ifndef Q_WS_QWS
QDesignerFormWindowInterface *form = QDesignerFormWindowInterface::findFormWindow(this);
if(form){
QDesignerFormEditorInterface *editor = form->core();
QExtensionManager *manager = editor->extensionManager();
QDesignerPropertySheetExtension *sheet;
sheet = qt_extension<QDesignerPropertySheetExtension*>(manager, this);
int propertyIndex = sheet->indexOf("button0Icon");
sheet->setChanged(propertyIndex, true);
sheet->setProperty(propertyIndex, getButton0Icon());
}
#endif
And:
int propertyIndex = this->metaObject()->indexOfProperty("button0Icon");
QMetaProperty property = this->metaObject()->property(propertyIndex);
property.write(this, QIcon());
Nothing seems to update the property list in the designer.
I have all properties, including all QIcon properties properly declared in the header file with Q_PROPERTY and assigned getter and setter functions.
To be clear, the icon values are indeed retained through each frame when compiled. So it is functioning, just unclear for most users.
If anyone has any experience with this or any ideas please let me know. Thanks.
I have discovered that QIcon does not store file names/paths. The file names are only used for the creation of the QIcon. I think this is most likely the reason I do not get any feedback in the Property Browser for my QIcon properties.
Instead I have chosen to hide this property in the designer and add three new ones. Three QUrl properties, each of which is used to supply an image file. I use three because I want to construct a QIcon that contains Modes/States for normal, disabled, and pressed operations.
I take each of these QUrls and save them in QStringLists behind the scenes so their values are stored. I then construct my QIcon using the file names provided from the QUrls.
I would much prefer to be using the native QIcon in the designer for this, any thoughts or feedback are appreciated.

How to change row height in QTextTable

I'm writing the complicated rich text editor, derived from QTextEdit class. It must be able to insert, resize, and apply various formatting to embedded tables.
I found function for setup column widths (setColumnWidthConstraints).
But there is no one to change _rows_ heights.
Is there any way to achieve this?
Example code:
void CustomTextEdit::insertTable (int rows_cnt, int columns_cnt)
{
QTextCursor cursor = textCursor ();
QTextTableFormat table_format;
table_format.setCellPadding (5);
// TODO: This call just changed the frame border height, not table itself.
//table_format.setHeight (50);
// Setup columns widths - all is working perfectly.
QVector <QTextLength> col_widths;
for (int i = 0; i < columns_cnt; ++i)
col_widths << QTextLength (QTextLength::PercentageLength, 100.0 / columns_cnt);
table_format.setColumnWidthConstraints (col_widths);
// ...But there is no similar function as setRowHeighConstraints for rows!
// Insert our table with specified format settings
cursor.insertTable (rows_cnt, columns_cnt, table_format);
}
it seems that you can use the setHTML(QString) or insertHTML(QString) functions to insert a stylesheet.
When using this function with a style sheet, the style sheet will only
apply to the current block in the document. In order to apply a style
sheet throughout a document, use QTextDocument::setDefaultStyleSheet()
instead.
ref: http://harmattan-dev.nokia.com/docs/platform-api-reference/xml/daily-docs/libqt4/qtextedit.html#insertHtml
appart from using shims....according to http://harmattan-dev.nokia.com/docs/platform-api-reference/xml/daily-docs/libqt4/richtext-html-subset.html you can set the font declaration.
Qt seems to have targeted the CSS2.1 specification, which is as followed.. http://www.w3.org/TR/CSS2/fonts.html#propdef-font
have you tried specifying the font within the table row.
pass the following string using insertHTML, where this string is delcared as a QString
<style>
table > tr {font-size: normal normal 400 12px/24px serif;}
</style>
If you just want to make rows taller than their text height would require, you could try inserting a 0xN transparent image in the first cell of the row (or 1xN if Qt won't let you do zero-width).
It might also be possible to set the table cell's top padding with QTextTableCellFormat::setTopPadding() or maybe set the top margin with QTextBlockFormat::setTopMargin(). But both padding and margins are added to the text layout height AFAIK, so neither of them is very good for setting an absolute height.
Have you looked at Calligra? Its libs/kotext and libs/textlayout libraries implement a custom QAbstractTextDocumentLayout with much richer table support than QTextEdit.
Insert a stylesheet using this->document()->setDefaultStyleSheet("css goes here");
See http://qt-project.org/doc/qt-5.0/qtwidgets/qtextedit.html#document-prop
and http://qt-project.org/doc/qt-5.0/qtgui/qtextdocument.html#defaultStyleSheet-prop
(links go to Qt5 docs, but these functions are available in Qt4 also.)

Infragistics grid scrolling issue

I have this code, which works fine if a cell in the IgGrid control is being edited:
var verticalContainer = $("#BookLabor_scrollContainer");
var topPos = verticalContainer.scrollTop();
$("#BookLabor").igGrid("option", "dataSource", blankLaborDS);
$('#BookLabor').igGrid('dataBind');
verticalContainer.scrollTop(topPos);
However, when I use an IgDialog that I have pop open on a grid cell with a button click event, this is not scrolling back to the row being edited:
var verticalContainer = $("#BookLabor_scrollContainer");
var topPos = verticalContainer.scrollTop();
$("#BookLabor").igGrid("option", "dataSource", blankLaborDS);
$('#BookLabor').igGrid('dataBind');
verticalContainer.scrollTop(topPos);
There is a virtual scroll method for the IgGrid, but the online documentation does not explain in detail how to use it.
Any tricks, tips, hints from all you Infragistics experts out there?
The scroll related API is very basic and what you are using is pretty much comparable:
.igGrid("scrollContainer") is merely a shorthand so you don't have to use #BookLabor_scrollContainer (it's an internal id)
.igGrid("virtualScrollTo", scrollContainerTop); is just like scroll top when you are using virtual scrolling, which you might be (can't tell without more code) so you might want to try that out.
HOWEVER, is there a reason to call dataBind after cell edit? ( I'm having a hard time finding a scenario for that). It is not intended by any means and it creates a lot of overhead with bigger data. If you need to update cell values you should be using the Updating API that does not require re-bind and will not require scroll after as well..see:
http://help.infragistics.com/jQuery/2012.2/ui.iggridupdating#methods
As for the dialog, the Updating again provides a row template that internally uses the dialog and I highly recommend that if row editing is acceptable. Sample:
http://www.infragistics.com/products/jquery/sample/grid/row-edit-template

Using images in QListWidget, is this possible?

I am using QT to create a chat messenger client. To display the list of online users, I'm using a QListWidget, as created like this:
listWidget = new QListWidget(horizontalLayoutWidget);
listWidget->setObjectName("userList");
QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(listWidget->sizePolicy().hasHeightForWidth());
listWidget->setSizePolicy(sizePolicy1);
listWidget->setMinimumSize(QSize(30, 0));
listWidget->setMaximumSize(QSize(150, 16777215));
listWidget->setBaseSize(QSize(100, 0));
listWidget->setContextMenuPolicy(Qt::CustomContextMenu);
Users are shown by constantly refreshing the list, like this: (Note: There are different channels, with different userlists, so refreshing it is the most efficient thing to do, as far as I know.)
void FMessenger::refreshUserlist()
{
if (currentPanel == 0)
return;
listWidget = this->findChild<QListWidget *>(QString("userList"));
listWidget->clear();
QList<FCharacter*> charList = currentPanel->charList();
QListWidgetItem* charitem = 0;
FCharacter* character;
foreach(character, charList)
{
charitem = new QListWidgetItem(character->name());
// charitem->setIcon(QIcon(":/Images/status.png"));
listWidget->addItem(charitem);
}
}
This has always worked perfectly. The line that I commented out is the one I have problems with: my current goal is to be able to display a user's online status with an image, which represents whether they are busy, away, available, etc. Using setIcon() does absolutely nothing though, apparently; the items still show up as they used to, without icons.
I'm aware that this is probably not the way this function needs to be used, but I have found little documentation about it online, and absolutely no useful examples of implementations. My question is, can anybody help me with fixing this problem?
This is how you may conduct your debugging:
Try the constructor that has both icon and text as arguments.
Try to use that icon in another context to ensure it is displayable (construct a QIcon with same argument and use it elsewhere, e.g. QLabel!).
Use icon() from the QListWidgetItem to receive back the icon and then look at that QIcon.
Create a new QListWidget, change nothing, and ordinarily add some stock items in your MainWidget's constructor. See if the icons show up there.