How do you figure out/determine (either from a control bar, or from the frame it is attached to) which side of the frame a CControlBar is attached to?
I know you can:
determine whether a controlbar is floating via BOOL IsFloating( ) const;
tell a controlbar which side of a frame it is allowed to connect to CBRS_ALIGN_TOP, AFX_IDW_DOCKBAR_TOP
But I don't know how to retrieve which side it has been docked to. Hope there is a method like CurrentlyDockedTo() which would return either CBRS_ALIGN_TOP, AFX_IDW_DOCKBAR_TOP ...
I am looking for the fastest way to figure out how much gray space is left in the main window ... the size of the gray rectange
You should be able to use GetBarStyle:
https://msdn.microsoft.com/en-us/library/6y1e7ff1.aspx
I found a very simple solution to my question. Exactly the answer I needed. The initial hint which led me on the correct path was found in the following post:
Detecting when a CControlBar's docking state has changed
The code which I was asking for was the following:
CPtrList& list = this->m_listControlBars;
POSITION pos = list.GetHeadPosition();
int total_cntrl_bars_found = 0;
while(pos)
{
CControlBar* pBar = (CControlBar*)list.GetNext(pos);
if(pBar)
{
if(!pBar->IsFloating())
{
total_cntrl_bars_found++;
int total_matched_styles = 0;
DWORD bar_style = pBar->GetBarStyle();
if(bar_style & CBRS_ORIENT_VERT)
{
// Then the bar is vertially oriented
// Will additionally also pass either the
// right oriented or left oriented check depending
total_matched_styles++;
}
if(bar_style & CBRS_ORIENT_HORZ)
{
// Then the bar is vertially oriented
total_matched_styles++;
}
if(bar_style & CBRS_ALIGN_RIGHT)
{
// Then the bar is right aligned
total_matched_styles++;
}
if(bar_style & CBRS_ALIGN_LEFT)
{
// Then the bar is left aligned
total_matched_styles++;
}
// There is also a check for top align
// and bottom aligned
}
}
}
here is some more info on GetBarStyle()
https://msdn.microsoft.com/en-us/library/6y1e7ff1.aspx
Related
I tried this code to get the first visible row in a scrolling Table inside a BorderLayout.CENTER, but it didn't work, seems the points returned do not reflect the visible cells, unless I am missing a sort of calculation,
thank you for your insights,
#Override
protected void onScrollY(int scrollY) {
super.onScrollY(scrollY); //To change body of generated methods, choose Tools | Templates.
Component c=getComponentAt(50, scrollY);
if (c instanceof Table){
System.err.println("table "+getWidth()+" "+getHeight()+" s "+scrollY);
return;
}
Button b=(Button) c;
System.err.println("c: "+b.getText());
}
getComponentAt(x,y) takes absolute (screen) coordinates. The scrollY value is a relative coordinate in that container.
So what you want is something like:
Component c = getComponentAt(getAbsoluteX()+50, getAbsoluteY() + scrollY)
Also worth nothing that getComponentAt(x,y) will only return components that are focusable or have been set to grab pointer events. If you just want to find the first paintable immediate child of this container, and you're using a BoxLayout.Y_AXIS layout, then you might be better to just iterate through the children until you find one where y is at least the scrollY.
e.g.
Component c = null;
for (Component child : this) {
if (child.getY() + child.getHeight() > scrollY) {
c = child;
break;
}
}
....
I add my program two RichEdit which the one displays binary contents and the another shows the index of the byte. I hope these two edit always anchor on the same position while/after scrolling.
A possible way is to handle the main RichEdit's WM_VSCROLL and WM_MOUSEWHEEL message and pass the message and parameters to the second RichEdit. I've tried this but I found that the two edits aligned not very well. And the other disadvantage is the both RichEdits' scroll bar needs to be enabled, if I only enable one, the another can't receive WM_MOUSEWHEEL message, but I hope one scroll bar displayed only.
The second way I've tried is using a timer and synchronize with LINESCROLL regularly by the time (< 10ms is better). This works well most of the time, but sometimes still have the unaligned issue.
Is there a better solution to handle this kind of demand?
//---------------------------------------------------------------------------
void __fastcall TBinaryEdit::Timer1Timer(TObject *Sender)
{
int srcLine = 0;
int trgLine = 0;
if (Sender == Timer1) {
srcLine = GetRichEditLineNo(MainEdit);
trgLine = GetRichEditLineNo(IndexEdit);
if (srcLine != trgLine) {
SendMessage(IndexEdit->Handle, EM_LINESCROLL, 0, srcLine - trgLine);
}
}
}
//---------------------------------------------------------------------------
int TBinaryEdit::GetRichEditLineNo(TRichEdit* RE)
{
int line;
int wordpos;
TRect rt;
POINTL pt;
SendMessage(RE->Handle, EM_GETRECT, 0, LPARAM(&rt));
pt.x = RE->Left + rt.left;
pt.y = RE->Top + rt.top;
wordpos = SendMessage(RE->Handle, EM_CHARFROMPOS, 0, LPARAM(&pt));
line = SendMessage(RE->Handle, EM_LINEFROMCHAR, wordpos, 0);
return line;
}
Thanks for your help. I've found a simple solution for my short-term need.
As I mentioned before, the second RichEdit's scroll bar should be enabled for receiving WM_MOUSEWHEEL message, but I don't like both edit have scroll bar displayed. For this reason, I use EM_LINESCROLL instead to replace the mouse wheel message. I write a sub class derive the TRichEdit and overwrite its WM_MOUSEWHEEL handler, then pass EM_LINESCROLL message with the mouse wheel's delta value to both RichEdits.
int zDelta = GET_WHEEL_DELTA_WPARAM(Message.WParam);
int scroll = zDelta == -120 ? 1 : -1;
SendMessage(MainEdit->Handle, EM_LINESCROLL, 0, scroll);
SendMessage(IndexEdit->Handle, EM_LINESCROLL, 0, scroll);
This makes the text vertical offset in RichEdits be aligned. But I think there must be better solution, I will keep research for improvement.
I am trying to make a program where you are allowed to select between an option of shapes, and then drawing it. To allow for multiple shapes I created a vector of a class which creates shapes (Shapes are set up with the chosen function). My problem is the mouse click is too long, so it assigns it to everything in the vector, so you can't create a new shape. Is there a problem in my logic, or is there a problem in the code?
Here is my attempt:
for (auto& it : onCanvas) {
if (Mouse::isButtonPressed(Mouse::Left)) {
if (mousepointer.getGlobalBounds().intersects(circleOption.getGlobalBounds())) {
it.chosen(circles);
}
if (mousepointer.getGlobalBounds().intersects(rectOption.getGlobalBounds())) {
it.chosen(rectangle);
}
if (mousepointer.getGlobalBounds().intersects(triOption.getGlobalBounds())) {
it.chosen(triangles);
}
if (mousepointer.getGlobalBounds().intersects(it.shape.getGlobalBounds()) || it.dragging) {
it.shape.setPosition(mousepointer.getPosition());
it.dragging = true;
}
}
if (!Mouse::isButtonPressed) {
it.dragging = false;
}
win.draw(it.shape);
}
Your source-code is a bit incomplete (what is onCanvas and mousepointer). But I guess the problem is that this snippet is called multiple times while your mouse is clicked. To avoid that you can do two thing.
In the first solution you use events, so you only add shapes when the state of the mousebutton changes (you can additionally listen to the MouseButtonReleased to simulate a full click):
if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
// Hit Detection
}
}
or second solution you remember the last state of the button (probably do the mouse check once outside of the for loop):
bool mouse_was_up = true;
if (mouse_was_up && Mouse::isButtonPressed(Mouse::Left)) {
mouse_was_up = false;
for (auto& it : onCanvas) {
// Hit Detection
}
}
else if (!Mouse::isButtonPressed(Mouse::Left))
mouse_was_up = true;
I would rather stick to the first solution because when your click is too short and your gameloop is in another part of the game logic, you can miss the click.
I want to make 4 clicks using mouse in the client area. Once the 4th click is done, the 4 points should be connected to form a shape.I did this using the following code.(I am using MFC).
void CChildView::OnLButtonDown(UINT nFlags,CPoint point)
{
CDC* pDC=GetDC();
if(m_iPointCount==1)
{
m_FirstPoint.x=point.x;
m_FirstPoint.y=point.y;
pDC->TextOut(m_FirstPoint.x,m_FirstPoint.y,"1");
rgn1.CreateEllipticRgn((m_FirstPoint.x-50),(m_FirstPoint.y-50),(m_FirstPoint.x+50),(m_FirstPoint.y+50));
}
if(m_iPointCount==2)
{
m_SecondPoint.x=point.x;
m_SecondPoint.y=point.y;
pDC->TextOut(m_SecondPoint.x,m_SecondPoint.y,"2");
rgn2.CreateEllipticRgn((m_SecondPoint.x-50),(m_SecondPoint.y-50),(m_SecondPoint.x+50),(m_SecondPoint.y+50));
}
if(m_iPointCount==3)
{
m_ThirdPoint.x=point.x;
m_ThirdPoint.y=point.y;
pDC->TextOut(m_ThirdPoint.x,m_ThirdPoint.y,"3");
rgn3.CreateEllipticRgn((m_ThirdPoint.x-50),(m_ThirdPoint.y-50),(m_ThirdPoint.x+50),(m_ThirdPoint.y+50));
}
if(m_iPointCount==4)
{
m_FourthPoint.x=point.x;
m_FourthPoint.y=point.y;
pDC->TextOut(m_FourthPoint.x,m_FourthPoint.y,"4");
rgn4.CreateEllipticRgn((m_FourthPoint.x-50),(m_FourthPoint.y-50),(m_FourthPoint.x+50),(m_FourthPoint.y+50));
pDC->MoveTo(m_FirstPoint.x,m_FirstPoint.y);
pDC->LineTo(m_SecondPoint.x,m_SecondPoint.y);
pDC->LineTo(m_ThirdPoint.x,m_ThirdPoint.y);
pDC->LineTo(m_FourthPoint.x,m_FourthPoint.y);
pDC->LineTo(m_FirstPoint.x,m_FirstPoint.y);
}
m_iPointCount++;
}
Each time the point count is incremented.I have also created 4 regions around 4 points.What I want to do now is, when I click in any of the regions I created and drag it to a new place the point should move to the new place where the mouse button is released after dragging. So that the shape is changed. This should be applicable to all the 4 regions.
I know I have to use Mousemove and LButtonUp functions but I have no idea how to do it. Pls help .
Hi I finally figured out how to do this.
The OnPaint event is as follows:
void CChildView::OnPaint()
{
CPaintDC dc(this); // device context for painting
{
dc.MoveTo(m_FirstPoint.x,m_FirstPoint.y);
dc.LineTo(m_SecondPoint.x,m_SecondPoint.y);
dc.LineTo(m_ThirdPoint.x,m_ThirdPoint.y);
dc.LineTo(m_FourthPoint.x,m_FourthPoint.y);
dc.LineTo(m_FirstPoint.x,m_FirstPoint.y);
}
}
The LButtonDown is as follows:
void CChildView::OnLButtonDown(UINT nFlags,CPoint point)
{
CDC* pDC=GetDC();
if(m_iPointCount==1)
{
m_FirstPoint.x=point.x;
m_FirstPoint.y=point.y;
pDC->TextOut(m_FirstPoint.x,m_FirstPoint.y,"1");
rgn1.CreateEllipticRgn((m_FirstPoint.x-50),(m_FirstPoint.y-50),(m_FirstPoint.x+50),(m_FirstPoint.y+50));
}
if(m_iPointCount==2)
{
m_SecondPoint.x=point.x;
m_SecondPoint.y=point.y;
pDC->TextOut(m_SecondPoint.x,m_SecondPoint.y,"2");
rgn2.CreateEllipticRgn((m_SecondPoint.x-50),(m_SecondPoint.y-50),(m_SecondPoint.x+50),(m_SecondPoint.y+50));
}
if(m_iPointCount==3)
{
m_ThirdPoint.x=point.x;
m_ThirdPoint.y=point.y;
pDC->TextOut(m_ThirdPoint.x,m_ThirdPoint.y,"3");
rgn3.CreateEllipticRgn((m_ThirdPoint.x-50),(m_ThirdPoint.y-50),(m_ThirdPoint.x+50),(m_ThirdPoint.y+50));
}
if(m_iPointCount==4)
{
m_FourthPoint.x=point.x;
m_FourthPoint.y=point.y;
pDC->TextOut(m_FourthPoint.x,m_FourthPoint.y,"4");
rgn4.CreateEllipticRgn((m_FourthPoint.x-50),(m_FourthPoint.y-50),(m_FourthPoint.x+50),(m_FourthPoint.y+50));
InvalidateRect(0);
}
if(m_iPointCount>4)
{
if(PtInRegion(rgn1,point.x,point.y))
{
m_fflag=true;
}
if(PtInRegion(rgn2,point.x,point.y))
{
m_sflag=true;
}
if(PtInRegion(rgn3,point.x,point.y))
{
m_tflag=true;
}
if(PtInRegion(rgn4,point.x,point.y))
{
m_foflag=true;
}
}
m_iPointCount++;
}
The MouseMove as follows:
void CChildView::OnMouseMove(UINT nFlags,CPoint point)
{
if(m_iPointCount>4)
if((nFlags & MK_LBUTTON)==MK_LBUTTON)
{
if(m_fflag==true)
{
m_FirstPoint=point;
InvalidateRect(0);
}
if(m_sflag==true)
{
m_SecondPoint=point;
InvalidateRect(0);
}
if(m_tflag==true)
{
m_ThirdPoint=point;
InvalidateRect(0);
}
if(m_foflag==true)
{
m_FourthPoint=point;
InvalidateRect(0);
}
}
}
The LButtonUp event is as follows:
void CChildView::OnLButtonUp(UINT nFlags,CPoint point)
{
CDC* pDC=GetDC();
if(m_fflag==true)
{
m_fflag=false;
rgn1.DeleteObject();
rgn1.CreateEllipticRgn((m_FirstPoint.x-50),(m_FirstPoint.y-50),(m_FirstPoint.x+50),(m_FirstPoint.y+50));
}
if(m_sflag==true)
{
m_sflag=false;
rgn2.DeleteObject();
rgn2.CreateEllipticRgn((m_SecondPoint.x-50),(m_SecondPoint.y-50),(m_SecondPoint.x+50),(m_SecondPoint.y+50));
}
if(m_tflag==true)
{
m_tflag=false;
rgn3.DeleteObject();
rgn3.CreateEllipticRgn((m_ThirdPoint.x-50),(m_ThirdPoint.y-50),(m_ThirdPoint.x+50),(m_ThirdPoint.y+50));
}
if(m_foflag==true)
{
m_foflag=false;
rgn4.DeleteObject();
rgn4.CreateEllipticRgn((m_FourthPoint.x-50),(m_FourthPoint.y-50),(m_FourthPoint.x+50),(m_FourthPoint.y+50));
}
}
Here is how this works:
1)An integer m_iPointCount is initialized to 1. This is used to store the number of points.
2) Four flags are initially set to false m_fflag=false;m_sflag=false;
m_tflag=false;m_foflag=false;(Four flags corresponds to four points of the polygon).
3)When the mouse is clicked for first 4 times the 4 points are saved in m_Firstpoint,m_Secondpoint,m_Thirdpoint and m_Fourthpoint.Correspondingly four regions are created(rgn1,rgn2,rgn3,rgn4 near to the 4 points). The 4 points are connected to form a polygon.
4)When the click is made for the 5th time(after we get the polygon),the check is made using if condition to find out the point lies in any one of the 4 regions.Accordingly the flags are set to true.(If the point lies in rgn1 then m_fflag is set to true and so on).
5)Consider the 5th click is made in rgn1 and now m_fflag is true,and the mouse is moved,Here the points used to draw the polygon in the paint message is updated and paint method is called using InvalidateRect(0). The polygon is redrawn.The m_Firstpoint is now updated to the new position.
6)When the mouse button is released after dragging,the flag is set to false and the old region is deleted and created near the new point.So that the region is also updated.
7) I have explained it for the first point, This is applicable for all the points.
Thanks.
In my game there are certain zombies coming from top of the screen.I have stored all zombies sprites in an CCArray.Then using foreach loop I am making them falling down.
I just want to perform combo.It means that whenever I kill a zombie on tap, the combo_counter increases.
On killing two consecutive zombies the combo_counter goes to 2 but if I tap at any other location on the screen the combo_counter should go to 0.
So my problem is how to detect whether I have not tapped a zombie and tapped anyother place on the screen.I am attaching my code also of cctouchbegan method
zombies is a CCArray where all zombie sprites are stored
void Level1::ccTouchesBegan(cocos2d::CCSet *pTouch, cocos2d::CCEvent *pEvent)
{
CCTouch* touch = (CCTouch*)(pTouch->anyObject());
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
CCObject* touchedzombie;
CCARRAY_FOREACH(zombies, touchedzombie)
{
if(!((CCSprite*) touchedzombie)->isVisible())
continue;
//
if(((CCSprite*)touchedzombie)==zombies->objectAtIndex(0))
{
// if((CCSprite*(touchedzombie)==zombies-))
if(touchedzombie!=NULL&&((CCSprite*)touchedzombie)->boundingBox().containsPoint(location))
{
this->setScoreonGame();
combo_counter++;
CCString *comboString=CCString::createWithFormat("comboX %d",combo_counter);
zombies_left--;
CCLOG("left = %d",zombies_left);
CCSize tt=((CCSprite*)touchedzombie)->getContentSize();
CCPoint pos_of_sprite=((CCSprite*)touchedzombie)->getPosition();
int rand_die1=Level1::random1();
CCString *str = CCString::createWithFormat("z2%d.png", rand_die1);
changedSprite = CCSprite::create(str->getCString());
CCLOG("Inside index 0");
((CCSprite*)touchedzombie)->setVisible(false);
changedSprite->setPositionX(pos_of_sprite.x);
changedSprite->setPositionY(pos_of_sprite.y);
changedSprite->setScaleX(Utils::getScaleX());
changedSprite->setScaleY(Utils::getScaleY());
this->addChild(changedSprite);
combo=CCLabelTTF::create(comboString->getCString(), "HoboStd", 50);
combo->setColor(ccRED);
combo->setPosition((ccp(changedSprite->getContentSize().width*0.50,changedSprite->getContentSize().height*1.05)));
changedSprite->addChild(combo,40);
this->runAction(CCSequence::create(delayAction,
callSelectorAction,
NULL));
this->removeChild( ((CCSprite*)touchedzombie),true);
this->Level1::reloadZombies();
// touchedzombie=NULL;
}
}
if(((CCSprite*)touchedzombie)==zombies->objectAtIndex(3))
{
// if((CCSprite*(touchedzombie)==zombies-))
if(touchedzombie!=NULL&&((CCSprite*)touchedzombie)->boundingBox().containsPoint(location))
{
// iftouched++;
this->setScoreonGame();
combo_counter++;
CCString *comboString=CCString::createWithFormat("comboX %d",combo_counter);
zombies_left--;
CCLOG("left = %d",zombies_left);
CCSize tt=((CCSprite*)touchedzombie)->getContentSize();
CCPoint pos_of_sprite=((CCSprite*)touchedzombie)->getPosition();
int rand_die1=Level1::random1();
CCString *str = CCString::createWithFormat("z2%d.png", rand_die1);
changedSprite3 = CCSprite::create(str->getCString());
// CCLOG("%s",str->getCString());
// CCLOG("Sprite Toucheddd");
CCLOG("Inside index 4");
// CCLog("width= %f height =%f",tt.width,tt.height);
// CCLog("x location =%f y location =%f",location.x,location.y);
// CCLog("Positon of Sprite X=%f Y=%f",pos_of_sprite.x,pos_of_sprite.y);
((CCSprite*)touchedzombie)->setVisible(false);
changedSprite3->setPositionX(pos_of_sprite.x);
changedSprite3->setPositionY(pos_of_sprite.y);
changedSprite3->setScaleX(Utils::getScaleX());
changedSprite3->setScaleY(Utils::getScaleY());
this->addChild(changedSprite3);
combo=CCLabelTTF::create(comboString->getCString(), "HoboStd", 50);
combo->setColor(ccRED);
combo->setPosition((ccp(changedSprite3->getContentSize().width*0.50,changedSprite3->getContentSize().height*1.05)));
changedSprite3->addChild(combo,40);
this->runAction(CCSequence::create(delayAction,
callSelectorAction3,
NULL));
this->removeChild( ((CCSprite*)touchedzombie),true);
this->Level1::reloadZombies();
touchedzombie=NULL;
}
//..upto 9 indexes...
}
}
First of all, it is not neccesary to do this checks : if(((CCSprite*)touchedzombie)==zombies->objectAtIndex(0))
How CCARRAY_FOREACH works, is it takes each object from the provided CCArray and assigns it to your touchedZombie variable - this means that if there are 10 elements in the array, this code will be run 10 times (exactly!). This means that with the first run, you will fall into the first if check (the one with objectAtIndex(0), with the second it will fall into the if check with objectAtIndex(1). Removing this if's not will not only speed up your function, but also tidy it up.
This would save you a lot of space, plus if you wanted to change something you would only have to do it in one place, which is safer.
Ok, to the problem at hand :
I see two solutions to this :
Leaving your code : you should move the combo code from the if blocks, and replace it with a flag. This flag should be set to false at the beginning of ccToucheBegan, and if you you detect a touch on a zombie, set it to true. Then after the CCARRAY_FOREACH block, this flag will tell you if there was a tap on a zombie or not. Change your combo accordingly.
Changing your code : You could also make the zombies CCMenuItemImages - this way they would have a different callback function than the rest of the screen. So whenever the ccTouchBegan method would be fired, you will know that it wasn't a zombie that was touched.
I hope everything is clear, if not - let me know.