How to center a widget in QScrollArea? - c++

Constructor:
ScrollArea::ScrollArea(...)
{
...
end = myItems.count();
for(int i=0; i<end; i++)
{
scrollItems.append(new ScrollItem(myItems.at(i), 0, width, i, this));
}
scrollArea->setWidget(this); //must be last for auto-scrolling to work
}
Member function:
void ScrollArea::updateSelection(int selection)
{
foreach(ScrollItem* item, scrollItems)
{
if(item->updateSelection(selection, 0))
{
scrollArea->ensureWidgetVisible(item);
}
}
}
After running ScrollArea::updateSelection, it looks like this:
I want it to look like this:
Google returns a mis-titled question (as far as I can tell: Place widget in center of QScrollArea) and a bunch of junk.

Still don't know why QScrollArea::ensureWidgetVisible doesn't work, even with explicit margins, but I found something that does:
void ScrollArea::updateSelection(int selection)
{
int item = -1;
int i = scrollItems.count();
while(i)
{
i--;
if(scrollItems.at(i)->updateSelection(selection, 0))
{
item = i;
}
}
if(item < 0)
{
return;
}
i = scrollItems.first()->height();
item *= i;
item += i / 2;
//item is now the position that should be centered
scrollArea->verticalScrollBar()->setValue(
item - (scrollArea->height() / 2)
);
}
So I'm basically brute-forcing what I want instead of having the library do it. (and fail)

Related

Not able to see List in window initially

I want to display list items in a separate window. But when the window opens it doesn't display the list. I can click the list item but I cannot see it. If I click on data it appears one by one.Also, when I scroll down the list it displays the data.
I have tired using
m_bList_index.UpdateData(FALSE);
m_bList_index.UpdateWindow();
m_bList.UpdateData(FALSE);
m_bList.UpdateWindow();
at the last of the DisplayList() function, but that didn't resolve the issue. Below is the code which I want to edit.
CListBox m_bList_index;
CMyListBox m_bList;
BOOL CBatch::OnInitDialog()
{
CDialog::OnInitDialog();
m_status.Empty();
m_bIndex.Empty();
m_elapsed_time.Empty();
m_estimated_time.Empty();
CenterWindow();
m_bList.CreateColumn();
DisplayList();
return TRUE;
// return TRUE unless you set the focus to a control
}
void CBatch::DisplayList()
{
unsigned int size;
m_bList_title.ResetContent();
m_bList_title.SetHorizontalExtent(2000);
m_bList_title.InsertString(0, theApp.m_pFieldBTitleStr);
theApp.bCheckList->SetSortingType(theApp.checkList->GetSortingType());
theApp.bCheckList->Sort();
size = theApp.bCheckList->GetSize();
m_bList_index.SetRedraw(FALSE);
m_bList_index.ResetContent();
m_bList_index.SetHorizontalExtent(2000);
m_bList.SetRedraw(FALSE);
m_bList.DeleteAllItems();
m_bList.SetHorizontalExtent(2000);
char ColumnName[256];
char strColumnValue[256];
double fColumnValue;
for (unsigned int i = 0; i < size; i++)
{
char buffer[255];
int index = 0;
if(m_bList.m_SerialNo)
{
sprintf(buffer,"%d",i+1);
m_bList.InsertItem(i, buffer,0);
index = 0;
}
else
{
theApp.bCheckList->m_checkArray[i]->get((CV_CHECK_FIELD)(m_bList.ListColumns[0]),buffer);
m_bList.InsertItem(i, buffer,0);
index = 1;
}
for(; index < m_bList.NoofColumns; index++)
{
LV_COLUMN rightjust;
rightjust.mask = LVCF_FMT;
rightjust.fmt = LVCFMT_RIGHT;
m_bList.SetColumn(index+m_bList.m_SerialNo,&rightjust);
memset(buffer,0x0,256);
theApp.bCheckList->m_checkArray[i]->get((CV_CHECK_FIELD)(m_bList.ListColumns[index]),buffer);
if ( (m_bList.ListColumns[index] == CV_CHECK_FIELD_FILELOCATION) ||
(m_bList.ListColumns[index] == CV_CHECK_FIELD_POSTED_DATE) ||
(m_bList.ListColumns[index] == CV_CHECK_FIELD_STATUS))
strcpy(buffer, buffer);
}
m_bList.SetItemText(i,index+m_bList.m_SerialNo,buffer);
}
}
m_bList.SetSel(0, TRUE);
m_bList.SetRedraw(TRUE);
m_bList_index.SetRedraw(TRUE);
UpdateData(FALSE);
}

How to limit a decrement?

There is a initial game difficulty which is
game_difficulty=5 //Initial
Every 3 times if you get it right, your difficulty goes up to infinity but every 3 times you get it wrong, your difficulty goes down but not below 5. So, in this code for ex:
if(user_words==words) win_count+=1;
else() incorrect_count+=1;
if(win_count%3==0) /*increase diff*/;
if(incorrect_count%3==0) /*decrease difficulty*/;
How should I go about doing this?
Simple answer:
if(incorrect_count%3==0) difficulty = max(difficulty-1, 5);
But personally I would wrap it up in a small class then you can contain all the logic and expand it as you go along, something such as:
class Difficulty
{
public:
Difficulty() {};
void AddWin()
{
m_IncorrectCount = 0; // reset because we got one right?
if (++m_WinCount % 3)
{
m_WinCount = 0;
++m_CurrentDifficulty;
}
}
void AddIncorrect()
{
m_WinCount = 0; // reset because we got one wrong?
if (++m_IncorrectCount >= 3 && m_CurrentDifficulty > 5)
{
m_IncorrectCount = 0;
--m_CurrentDifficulty;
}
}
int GetDifficulty()
{
return m_CurrentDifficulty;
}
private:
int m_CurrentDifficulty = 5;
int m_WinCount = 0;
int m_IncorrectCount = 0;
};
You could just add this as a condition:
if (user words==words) {
win_count += 1;
if (win_count %3 == 0) {
++diff;
}
} else {
incorrect_count += 1;
if (incorrect_count % 3 == 0 && diff > 5) {
--diff
}
}
For example:
if(win_count%3==0) difficulty++;
if(incorrect_count%3==0 && difficulty > 5) difficulty--;
This can be turned into a motivating example for custom data types.
Create a class which wraps the difficulty int as a private member variable, and in the public member functions make sure that the so-called contract is met. You will end up with a value which is always guaranteed to meet your specifications. Here is an example:
class Difficulty
{
public:
// initial values for a new Difficulty object:
Difficulty() :
right_answer_count(0),
wrong_answer_count(0),
value(5)
{}
// called when a right answer should be taken into account:
void GotItRight()
{
++right_answer_count;
if (right_answer_count == 3)
{
right_answer_count = 0;
++value;
}
}
// called when a wrong answer should be taken into account:
void GotItWrong()
{
++wrong_answer_count;
if (wrong_answer_count == 3)
{
wrong_answer_count = 0;
--value;
if (value < 5)
{
value = 5;
}
}
}
// returns the value itself
int Value() const
{
return value;
}
private:
int right_answer_count;
int wrong_answer_count;
int value;
};
And here is how you would use the class:
Difficulty game_difficulty;
// six right answers:
for (int count = 0; count < 6; ++count)
{
game_difficulty.GotItRight();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
// three wrong answers:
for (int count = 0; count < 3; ++count)
{
game_difficulty.GotItWrong();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
// one hundred wrong answers:
for (int count = 0; count < 100; ++count)
{
game_difficulty.GotItWrong();
}
// check wrapped value:
std::cout << game_difficulty.Value() << "\n";
Output:
7
6
5
Once you have a firm grasp on how such types are created and used, you can start to look into operator overloading so that the type can be used more like a real int, i.e. with +, - and so on.
How should I go about doing this?
You have marked this question as C++. IMHO the c++ way is to create a class encapsulating all your issues.
Perhaps something like:
class GameDifficulty
{
public:
GameDifficulty () :
game_difficulty (5), win_count(0), incorrect_count(0)
{}
~GameDifficulty () {}
void update(const T& words)
{
if(user words==words) win_count+=1;
else incorrect_count+=1;
// modify game_difficulty as you desire
if(win_count%3 == 0)
game_difficulty += 1 ; // increase diff no upper limit
if((incorrect_count%3 == 0) && (game_difficulty > 5))
game_difficulty -= 1; //decrease diff;
}
inline int gameDifficulty() { return (game_difficulty); }
// and any other access per needs of your game
private:
int game_difficulty;
int win_count;
int incorrect_count;
}
// note - not compiled or tested
usage would be:
// instantiate
GameDiffculty gameDifficulty;
// ...
// use update()
gameDifficulty.update(word);
// ...
// use access
gameDifficulty.gameDifficulty();
Advantage: encapsulation
This code is in one place, not polluting elsewhere in your code.
You can change these policies in this one place, with no impact to the rest of your code.

OpenGL/Glut: glutTimerFunc seems not to start

I would like to use glutTimerFunc to move the camera around the scene which is composed of some mesh models. The camera path is build with a Bezier curve like the following:
if(sel == MODE_CAMERA_MOTION) {
mode = MODE_CAMERA_MOTION;
stepsCounter = 0;
// Building camera track
int i, j, k;
for(j=0; j<MAX_CV; j++) {
tmpCV[j][0] = CV[j][0];
tmpCV[j][1] = CV[j][1];
tmpCV[j][2] = CV[j][2];
}
for(i=0; i<STEPS; i++) {
for(j=1; j<MAX_CV; j++) {
for(k=0; k<MAX_CV-j; k++) {
lerp(i/(float)(STEPS*10), tmpCV[k], tmpCV[k+1], tmpCV[k]);
}
}
cameraPosition[i][0] = tmpCV[0][0];
cameraPosition[i][1] = tmpCV[0][1];
cameraPosition[i][2] = tmpCV[0][2];
}
glutTimerFunc(250, moveCamera, STEPS);
}
where the moveCamera function is:
void moveCamera() {
if (mode == MODE_CAMERA_MOTION) {
camE[0] = cameraPosition[stepsCounter][0];
camE[1] = cameraPosition[stepsCounter][1];
camE[2] = cameraPosition[stepsCounter][2];
if(stepsCounter < STEPS) {
stepsCounter++;
}
else {
/* come back to the first point */
camE[0] = 8.8;
camE[1] = 4.9;
camE[2] = 9.0;
stepsCounter = 0;
}
glutPostRedisplay();
}
}
But nothing moves. Maybe I have misunderstood the behaviour of that function.
Where am I wrong?
The prototype to the function passed to glutTimerFunc should be
void (*func)(int value)
Where the last parameter of glutTimerFunc is the passed value. So your moveCamera should be:
void moveCamera( int STEPS )
Also, even so, the moveCamera function will be called once. You need to reregister at end of execution. This might be a possible solution:
// instead of global STEPS and stepsCounter, we decrement at reexecution
void moveCamera( int STEPS ) {
... do stuff
glutTimerFunc(250, moveCamera, STEPS-1 );
}

Store and pass array in MFC-single-document

I am doing a small project of drawing tool.
When button down, capture the start point. When mouse move, draw a line. When button up, capture the final point. I use line to draw a polygon, so I use array m_polygonx to store final point.x of a line, and m_polygony to store final point.y, uint m_count to count the numbers of final points.
Here is my code:
void CDrawToolView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_startRect=FALSE;
::ClipCursor(NULL);
dc.MoveTo(m_startPoint);
dc.LineTo(m_OldPoint);
dc.MoveTo(m_startPoint);
dc.LineTo(point);
m_count++;
m_polygonx[m_count] = point.x;
m_polygony[m_count] = point.y;
}
And then I pass the array to a dialog.
In my calling function:
void CDrawToolView::OnEditProperty()
{
CPropertyDlg dlg;
dlg.origin_x = m_startPoint.x;
dlg.origin_y = m_startPoint.y;
dlg.count = m_count;
for (int i=0; i < m_count ; i++)
{
dlg.polygonx[i] = m_polygonx[i];
dlg.polygony[i] = m_polygony[i];
}
if (dlg.DoModal() == IDOK)
{
m_startPoint.x = dlg.origin_x;
m_startPoint.y = dlg.origin_y;
m_count = dlg.count;
for (int i=0; i < dlg.count ; i++)
{
m_polygonx[i] = dlg.polygonx[i];
m_polygony[i] = dlg.polygony[i];
}
}
}
But the array does not stored and passed successfully. Could some one help me?

How do I made shooting multiple bullets function correctly using a for loop?

I'm working on a prototype for a shmup game in C++ using SDL...Right now I'm just trying to get the basics working without using classes. Now, I have it so it shoots multiple bullets, but it behaves strangely which I believe is because of the way the counter is reset...The bullets will appear and disappear, and some will keep blinking in the original spot they were shot at, and there will sometimes be a delay before any can be shot again even if the limit isn't on the screen...And sometimes the player character will suddenly jump way to the right and only be able to move up and down. How do I fix this so it smoothly shoots? I've included all relevent code...
[edit] Please note that I intend on cleaning it up and moving it all to a class once I get this figured out...This is just a simple prototype so I can have the basics of the game programmed in.
[edit2] ePos is the enemy position, and pPos is the player position.
//global
SDL_Surface *bullet[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
bool shot[10];
int shotCount = 0;
SDL_Rect bPos[10];
//event handler
case SDLK_z: printf("SHOT!"); shot[shotCount] = true; ++shotCount; break;
//main function
for(int i = 0; i <= 9; i++)
{
shot[i] = false;
bullet[i] = IMG_Load("bullet.png");
}
//game loop
for(int i = 0; i <= shotCount; i++)
{
if(shot[i] == false)
{
bPos[i].x = pPos.x;
bPos[i].y = pPos.y;
}
if(shot[i] == true)
{
bPos[i].y -= 8;
SDL_BlitSurface(bullet[i], NULL, screen, &bPos[i]);
if( (bPos[i].y + 16 == ePos.y + 16) || (bPos[i].x + 16 == ePos.x + 16) )
{
shot[i] = false;
}
else if(bPos[i].y == 0)
{
shot[i] = false;
}
}
}
if(shotCount >= 9) { shotCount = 0; }
Here is something like I was suggesting in the comment. It was just written off the top of my head but it gives you a general idea of what I'm talking about..
class GameObject
{
public:
int x;
int y;
int width;
int height;
int direction;
int speed;
GameObject()
{
x = 0;
y = 0;
width = 0;
height = 0;
direction = 0;
speed = 0;
}
void update()
{
// Change the location of the object.
}
bool collidesWidth(GameObject *o)
{
// Test if the bullet collides with Enemy.
// If it does, make it invisible and return true
}
}
GameObject bullet[10];
GameObject enemy[5];
while(true)
{
for(int x=0; x<=10;x++)
{
bullet[x].update();
for(int y=0;y<=5;y++)
{
if(bullet[x].collidesWith(&enemy[y])
{
// Make explosion, etc, etc.
}
}
}
}