bool win::checkIfFScreen(sf::RenderWindow &window)
{
TiXmlDocument doc;
TiXmlElement * fullscreen;
if(!doc.LoadFile("videoSettings.xml"))
{
fullscreen = new TiXmlElement( "Window" );
fullscreen->SetAttribute("Fullscreen: ", 0);
doc.LinkEndChild( fullscreen );
fullscreen->Attribute("Fullscreen: ");
std::cout << typeid(*fullscreen->Attribute("Fullscreen: ")).name() << std::endl;
doc.SaveFile("videoSettings.xml");
return false;
}
if(*(fullscreen->Attribute("Fullscreen: ")) == '0')
return false;
return true;
}
Idea:
So, I wanna store information about persons preference if he wants for the game to be fullscreen or windowed. I've created this bool function that checks if there is "videoSettings.xml" file and returns information about users preference. If the file doesn't exists it will be create with Fullscreen set to 0 (which basically means that the game will be windowed and the user could change it later in the game's settings).
Part that doesn't work:
if(*(fullscreen->Attribute("Fullscreen: ")) == '0')
return false;
After adding this two lines I've got Segmentation fault (core dumped).
It seems that that value is stored as char.
EDIT:
This lines solved everything :) .
TiXmlHandle docHandle ( &doc );
TiXmlElement *child = docHandle.FirstChild( "Window" ).ToElement();
if(child)
if(*child->Attribute("fullscreen") == '1')
return true;
else if(*child->Attribute("fullscreen") == '0')
return false;
Thank you #frasnian .
Your code has this:
TiXmlElement * fullscreen; // not initialized to anything here
if(!doc.LoadFile("videoSettings.xml")) // LoadFile returns true on success
{
fullscreen = new TiXmlElement( "Window" ); // okay
...
return false;
}
// question: if doc.LoadFile() succeeds, what is this going to do-
if(*(fullscreen->Attribute("Fullscreen: ")) == '0')
return false;
You are using fullscreen before it is initialized with anything.
On edit
In response to question in comment:
If loading the document succeeds, you need to get the root element with something like:
TiXmlElement* root = doc.FirstChildElement("Whatever"); // root element name
if (root){
TiXmlElement* el = root->FirstChildElement("Window"); // etc, etc,
When you have walked the document hierarchy to wherever your "Window" element is, use TiXmlElement::Attribute() or TiXmlElement::QueryAttribute() to get the value of the attribute (if it exists).
A better approach than walking the hierarchy with FirstChild/NextSibling, etc. (inherited by TiXmlElement from TiXmlNode) is probably to use handles. See the docs for TinyXML related to TiXmlHandle - the main docs page has an example that is pretty straightforward.
As a side note, the colon after the attribute name in your posted code should be removed (i.e. "fullscreen", not "Fullscreen:").
Also, this line:
fullscreen->Attribute("Fullscreen: ");
right after you call LinkEndChild() does not do anything.
Related
I am using Qt's QSyntaxHighlighter to color some C like syntax in a QML TextEdit
Everything works great except for multiline comments.
I am detecting them this way :
void highlightBlock(QString const& text) override {
bool inMultilineComment = previousBlockState() == STATES::COMMENT;
bool inSingleLineComment = false;
int previousIndex = 0;
QRegularExpression expr("(\\/\\*|\\*\\/|\\/\\/|\n)"); // will match either /**, /**, // or \n
QRegularExpressionMatchIterator it = expr.globalMatch(text);
while(it.hasNext()) {
QRegularExpressionMatch match = it.next();
const QString captured = match.captured(1);
if(captured == "/*" && !inSingleLineComment) {
inMultilineComment = true;
previousIndex = match.capturedStart(1);
}
if(captured == "*/" && inMultilineComment) {
inMultilineComment = false;
setFormat(previousIndex, match.capturedEnd(1) - previousIndex, _commentFormat);
}
if(captured == "//" && !inMultilineComment) {
inSingleLineComment = true;
}
if(captured == "\n" && inSingleLineComment) {
inSingleLineComment = false;
}
}
if(inMultilineComment) {
setFormat(previousIndex, text.size() - previousIndex, _commentFormat);
setCurrentBlockState(STATES::COMMENT);
}
else {
setCurrentBlockState(STATES::NONE);
}
}
It works until I take a multiline comment already colored and I remove the /* at the begining. Only the block that contains the /* is processed and recolored, but not the following ones, which means that they continue to appear commented when they are not.
Is there an easy way to tell QSyntaxHighlighter to re-process the following blocks to prevent such mis-colorations ?
I ran into this same problem recently and discovered that Qt actually should be handling this for you, assuming that you set your blockState correctly.
If you look at the sourceCode for QSyntaxHighlighterPrivate::reformatBlocks in the Qt5 source code, you'll see
while (block.isValid() && (block.position() < endPosition || forceHighlightOfNextBlock)) {
const int stateBeforeHighlight = block.userState();
reformatBlock(block);
forceHighlightOfNextBlock = (block.userState() != stateBeforeHighlight);
block = block.next();
}
retrieved from https://code.woboq.org/qt5/qtbase/src/gui/text/qsyntaxhighlighter.cpp.html#165
That code (which is fired by a contentsChange signal from the QTextDocument your highlighter is on) will iterate through each block (line) starting from the block that was just modified. Assuming that the state of the block changed based on the typing change that just happened, it will continue to process the following blocks. This means that you need to get your userState correct for every line and Qt should handle the rest.
Given the example
/*
* This is a comment
*
* That I made
*/
You would want to start in the condition where every line had the STATES::COMMENT set except for the last line which should be set to STATES::NONE. Once you do something like deleting the initial /* you need to make sure that the block state is reset to STATES::NONE. That will trigger Qt to rerun the next block, which will also need to change its state, etc.
In my (python) code, I ended up using a combination of print statements and real debugging to track the propagation of state changes and figured out where it was not correctly updating and breaking the chain of updates. Your code looks superficially correct, though I did not try to compile and run it, but I suspect there is a some case being triggered where the state is not being updated correctly after an edit.
void MainWindow::edit()
{
//Check if item is selected, if not return
const int row = list->currentRow();
if( row == -1 )
return;
EditWindow w( this, currentCategory() );
switch( currentCategory() )
{
case cApp:
{
App old = appList.at( row );
w.setApp( old );
if( w.exec() == QDialog::Rejected )
return;
if( old == w.app() ) return;
else old = w.app();
if( dm->updateApp( old ) ){
appList.replace( row, old );
list->item(row)->setText( old.name() );
}
break;
}
case cFilm:
{
Film old = filmList.at( row );
w.setFilm( old );
if( w.exec() == QDialog::Rejected )
return;
if( old == w.film() ) return;
else old = w.film();
if( dm->updateFilm( old ) ){
filmList.replace( row, old );
list->item(row)->setText( old.name() );
}
break;
}
case cSong:
{
Song old = songList.at( row );
w.setSong( old );
if( w.exec() == QDialog::Rejected )
return;
if( old == w.song() ) return;
else old = w.song();
if( dm->updateSong(old) ){
songList.replace( row, old );
list->item(row)->setText( old.name() );
}
break;
}
}
displayItem(row);
}
This code checks which category we have at the moment. Then it edits an app, a movie or a song (depends on the category). Then when I change some informations it writes these changes to the database and the global QLists, change the name in the QListWidget and displays the current item's information in a few labels (it's the last function).
As you can see it's the same code except that the QLists are different. Movies and songs work perfectly. I can change every detail and it automatically updates the name in the list.
But when I change the name of an app and click ok it doesn't change the name in the list and doesn't change the apps information in the QList.
However, when I go through it with a debugger and click on every single step the list changes the name and the information.
So basically what I am trying to ask is why does this code above work when using the debugger going through each step but not when just running it?
I guess that what you call "simple running" is actually using your IDE in "build to run" mode and you are in fact comparing a debug build with an optimised release build. The debugger properly initialises all memory to zero which doesn't happen in the release build.
Regardless of what you are doing, this behaviour is indicative of illegal memory access.
From your code everytime you use at() you are at risk of going out of bounds and I guess that is what is happening. You should check all instances of at() and also list->item(row) are not going out of bounds.
Furthermore using list is at risk of being confused with std::list, therefore this variable should be renamed.
In ActionScript, I can just check the .stage property of a DisplayObject, and if it's null, then the DisplayObject isn't on the display list. Is there a cocos2d equivalent?
I'm controlling my own touch system for buttons etc, and I want a quick way to ignore buttons that are registered but not actually on the screen. I'm currently checking against visible and parent, but that doesn't go all the way up the chain, so if I have a popup in memory that's not visible/attached to anything, and a button as a child inside that popup, the button check will pass (as it's visible and has a parent).
Aside from looping all the up until the scene, is there an easy way to check if a CCNode/CCSprite is on the display list?
Edit
Working on #HariKrishna's answer, this was the code I came up with as the cocos2d-x implementation wasn't exactly what I was looking for (e.g. if the parent of the node was nil, then it would return YES as it would never enter the check):
- (BOOL) hasVisibleParents
{
CCNode * p = self.parent;
while( true )
{
if( p == nil || !p.visible )
return NO;
if( [p isKindOfClass:[CCScene class]] )
return YES;
p = p.parent;
}
return YES;
}
You can use CCNode::isVisible() and CCControl::hasVisibleParents() which will internally go up to all the node hierarchy...
Thats the closest you can get for the same.
Example:
bool presentInDisplayList() {
if(isVisible() && hasVisibleParents())
return true;
else
return false;
}
Where hasVisibleParents() is, (Copied from Cocos2d-X Library)
bool CCControl::hasVisibleParents()
{
CCNode* pParent = this->getParent();
for( CCNode *c = pParent; c != NULL; c = c->getParent() )
{
if( !c->isVisible() )
{
return false;
}
}
return true;
}
This can be easily translated to Objective-C
I would like to start by saying thanks to everyone who takes some time to view this thread and try to help.
I have searched the Internet, and couldn't find an example of selecting tree view node that has label text as same as text of a string variable.
On MSDN I have found message TVM_GETISEARCHSTRING but I don't know if it can be used to solve my problem. Even if it can, I still don't know how to use it.
I have a string variable that holds text from database.
When program loads, tree view should have a node with the same text selected.
Please help with some instructions or code snippets, since I have no clue how to even start coding this.
I work in MS Visual Studio Express 2008, on Windows XP, in C++, using pure WIN32 API.
That would be all, again I thank everyone who tries to help.Thank you very very much!
EDIT:
Both answers are good for me, but I don't know how to mark them both, it seems that on this site only one answer can be accepted.
I couldn't have just neglected all the work both of them invested to help me, so I write this in order to try to repay to the Jonathan at least by officially stating that his solution is acceptable for me too, it is just that Tim's solution suits my coding style better.I will also upvote both answers.
The treeview control does not provide an API to search for a label. You will have to manually traverse the items and compare them to your string.
If your treeview is more than one level deep you will have to decide how to traverse the items (either depth first or breadth first). In case there are multiple items with the same label these strategies may return different items.
An implementation might look something like this:
// Helper function to return the label of a treeview item
std::wstring GetItemText( HWND hwndTV, HTREEITEM htItem )
{
static const size_t maxLen = 128;
WCHAR buffer[ maxLen + 1 ];
TVITEMW tvi = { 0 };
tvi.hItem = htItem; // Treeview item to query
tvi.mask = TVIF_TEXT; // Request text only
tvi.cchTextMax = maxLen;
tvi.pszText = &buffer[ 0 ];
if ( TreeView_GetItem( hwndTV, &tvi ) )
{
return std::wstring( tvi.pszText );
}
else
{
return std::wstring();
}
}
This is where the actual traversal takes place. The function is called recursively until no more items can be searched or a match has been found. This implementation uses a case-sensitive comparison (wstring::operator==( const wstring& )). If you need a different predicate you will have to modify the implementation as you see fit.
HTREEITEM FindItemDepthFirstImpl( HWND hwndTV, HTREEITEM htStart, const std::wstring& itemText )
{
HTREEITEM htItemMatch = NULL;
HTREEITEM htItemCurrent = htStart;
// Iterate over items until there are no more items or we found a match
while ( htItemCurrent != NULL && htItemMatch == NULL )
{
if ( GetItemText( hwndTV, htItemCurrent ) == itemText )
{
htItemMatch = htItemCurrent;
}
else
{
// Traverse into child items
htItemMatch = FindItemDepthFirstImpl( hwndTV, TreeView_GetChild( hwndTV, htItemCurrent ), itemText );
}
htItemCurrent = TreeView_GetNextSibling( hwndTV, htItemCurrent );
}
return htItemMatch;
}
The following function wraps the recursion and passes the root element as the starting point. This is the function you would call in your code. It will return an HTREEITEM if one is found, NULL otherwise.
HTREEITEM FindItem( HWND hwndTV, const std::wstring& itemText )
{
HTREEITEM htiRoot = TreeView_GetRoot( hwndTV );
return FindItemDepthFirstImpl( hwndTV, htiRoot, itemText );
}
Unfortunately there is no documented way to search a treeview by item label.
The TVM_GETISEARCHSTRING message returns the search string that the user has typed into the tree (incremental search mode) but it doesn't trigger a search or let you supply your own search string.
The only way to do it is by manually iterating the tree nodes and comparing the labels yourself. Below is an example function, beware that it is recursive and will use about half a KB of stack for every child level.
HTREEITEM TreeView_FindLabel(HWND hWnd, HTREEITEM hItemParent, LPCWSTR pszLabel)
{
TVITEM tvi;
wchar_t wchLabel[256];
for (tvi.hItem = TreeView_GetChild(hWnd, hItemParent); tvi.hItem;
tvi.hItem = TreeView_GetNextSibling(hWnd, tvi.hItem))
{
tvi.mask = TVIF_TEXT | TVIF_CHILDREN;
tvi.pszText = wchLabel;
tvi.cchTextMax = _countof(wchLabel);
if (TreeView_GetItem(hWnd, &tvi))
{
if (_wcsicmp(tvi.pszText, pszLabel) == 0)
return tvi.hItem;
if (tvi.cChildren)
{
HTREEITEM hChildSearch = TreeView_FindLabel(hWnd, tvi.hItem, pszLabel);
if (hChildSearch) return hChildSearch;
}
}
}
return 0;
}
This is not a particularly fast way of searching the tree. If you need to do lots of searches you would be better using a std::map to keep track of the labels and tree items yourself. For example,
std::map<std::wstring, HTREEITEM> mapTreeItems;
// whenever you add an item
HTREEITEM hItem = ListView_InsertItem(...);
mapTreeItems[strLabel] = hItem;
Then you can lookup tree items by label using the map. You just have to remember to update the map and erase labels whenever an item is deleted from the tree.
I am writing a multithreaded app. On the main thread is the main window which is a modeless dialog box. When the user clicks on the start button, it will create a new thread that does some stuff for a long time. On the main thread it will create a new modeless dialog box to display the status of that new thread, 1 per thread. I created kind of a template dialog box using the resource editor and I set a static text for the status to have an id of IDC_STATIC_NUMCYCLE. I poll the status of the threads during the OnIdle function. The updating of the status works with 1 thread only, but if I spawn more the static text for all will not update until the very end or if it is the only thread left running.
Declaration:
map<CSimDlg *, CSimulator *> simulations;
My OnIdle function:
BOOL CFGSim1App::OnIdle(LONG lCount)
{
CWinApp::OnIdle(lCount);
DWORD exitCode;
CString numOfCycle;
for (map<CSimDlg *, CSimulator *>::iterator iter = simulations.begin(); iter != simulations.end();)
{
// skip already finished threads
if (iter->second == NULL)
{
iter++;
continue;
}
if (GetExitCodeThread(iter->second->m_hThread, &exitCode))
{
if (exitCode == 0)
{
delete iter->second;
iter->second = NULL;
if (IsWindow(iter->first->m_hWnd))
{
iter->first->SetDlgItemText(IDC_STATIC_SIMSTATUS, L"Simulation done");
}
else
{
iter = simulations.erase(iter);
}
}
else
{
ULONG64 temp = iter->second->m_ul64NumOfCycle;
if (temp % 10000 == 0)
{
numOfCycle.Format(_T("%d"), temp);
iter->first->SetDlgItemText(IDC_STATIC_NUMCYCLE, numOfCycle);
}
iter++;
}
}
else
{
iter++;
}
}
return TRUE;
}
I am guessing the problem is with the id of the static text. Is there a way to work around this? Or do I need to declare a different id for each dialog box? Or is the problem elsewhere?
The (temp % 10000 == 0) condition is suspicious to me. You are assuming that temp will increment slowly enough that 10000 marks will be detected. This may not be the case. If you want to reduce GUI operations then introduce a "last count" variable for each thread, and update GUI only if temp is sufficiently larger than this variable, that is then set to temp.
BTW you don't need std::map if all you do with the container is to traverse trough it, and don't use special features of the map. It might as well be a list of std::pair, or list of some new structure. This new structure could hold the mentioned last count variable.
Your logic seems fine to me.
Maybe MFC could require a repaint request after the text change:
iter->first->SetDlgItemText(IDC_STATIC_NUMCYCLE, numOfCycle);
iter->first->Invalidate();
I'm sorry but currently I don't have MFC handy to test...