QLineEdit setSelection doesn't work - qt

I created a custom QLineEdit for timecode (a timecode looks like this : hh:mm:ss:ff) edition.
It react with the keyboard and the mouse. If the user edit the timecode with the mouse (draging up/down a couple of digit) the highlighting is wrong : it select all the characters from the cursor to the end. (ie: If I drag mm the selection will be mm:ss:ff).
In order to get rid of that, I use setSelection(x,2) which select only the wanted digit (verified using qDebug() << selectedText()) but the highlighting is still wrong :
#include "PhTimecodeEdit.h"
PhTimeCodeEdit::PhTimeCodeEdit(QWidget *parent) :
QLineEdit(parent),
_tcType(PhTimeCodeType25)
{
connect(this, SIGNAL(textChanged(QString)), this, SLOT(onTextChanged(QString)));
this->installEventFilter(this);
_mousePressed = false;
_selectedIndex = 0;
}
bool PhTimeCodeEdit::isTimeCode()
{
PhFrame frame;
QString text;
frame = PhTimeCode::frameFromString(this->text(),_tcType);
text = PhTimeCode::stringFromFrame(frame, _tcType);
if(text == this->text())
return true;
else
return false;
}
bool PhTimeCodeEdit::eventFilter(QObject *, QEvent *event)
{
switch (event->type()) {
case QEvent::MouseButtonPress:
_mousePressed = true;
_mousePressedLocation = static_cast<QMouseEvent *>(event)->pos();
if(_mousePressedLocation.x() > 110 and _mousePressedLocation.x() < 145) {
_selectedIndex = 0;
}
else if(_mousePressedLocation.x() > 145 and _mousePressedLocation.x() < 190) {
_selectedIndex = 3;
}
else if(_mousePressedLocation.x() > 190 and _mousePressedLocation.x() < 230) {
_selectedIndex = 6;
}
else if(_mousePressedLocation.x() > 230 and _mousePressedLocation.x() < 270) {
_selectedIndex = 9;
}
return true;
case QEvent::MouseButtonRelease:
_mousePressed = false;
return true;
case QEvent::MouseMove:
{
if(_mousePressed) {
int y = static_cast<QMouseEvent *>(event)->pos().y();
PhFrame currentFrame = PhTimeCode::frameFromString(this->text(), _tcType);
if(_selectedIndex == 0) {
if(_mousePressedLocation.y() > y)
currentFrame += 25 * 60 * 60;
else
currentFrame -= 25 * 60 * 60;
}
else if(_selectedIndex == 3) {
if(_mousePressedLocation.y() > y)
currentFrame += 25 * 60;
else
currentFrame -= 25 * 60;
}
else if(_selectedIndex == 6) {
if(_mousePressedLocation.y() > y)
currentFrame += 25;
else
currentFrame -= 25;
}
else if(_selectedIndex == 9) {
if(_mousePressedLocation.y() > y)
currentFrame++;
else
currentFrame--;
}
_mousePressedLocation.setY(y);
this->setText(PhTimeCode::stringFromFrame(currentFrame, _tcType));
setSelection(_selectedIndex,2);
}
return false;
}
default:
return false;
}
}
What should I do to get it right ?

I'm not sure, but your eventFilter is strange. It conflicts with mouse processing of QLineEdit.
Try to return QLineEdit::eventFilter(); in default section.
You didn't implement mouse tracking. You should disable it with mouse capture and overloading mouse*Event();. Mouse events processing should be disabled while you track manually mouse.
Reason of bug: mouse moving, that processed by QLineEdit overrides text selection that you set in eventFilter. It happens on mouse release.
Possible hotfix (dirty): implement your own slot for set selection and call it via Qt::QueuedConnection. So your direct call of setSelection will be processed after releasing of mouse.

Related

QTreeView: column resize from columns and not from headers?

Is there any way to allow the user to interactively resize the columns when headers are hidden?
You can install an event filter on the table's viewport and implement needed behavior manually. Below is a sample implementation.
Header:
#include <QTableView>
class Table_cell_resizer : public QObject {
Q_OBJECT
public:
explicit Table_cell_resizer(QTableView *view = 0);
protected:
bool eventFilter(QObject* object, QEvent* event);
private:
QTableView* m_view;
//max distance between mouse and a cell, small enough to trigger resize
int m_sensibility;
//variables for saving state while dragging
bool m_drag_in_progress;
Qt::Orientation m_drag_orientation;
int m_drag_section;
int m_drag_previous_pos;
// check if mouse_pos is around right or bottom side of a cell
// (depending on orientation)
// and return the index of that cell if found
QModelIndex index_resizable(QPoint mouse_pos, Qt::Orientation orientation);
};
Source:
#include "Table_cell_resizer.h"
#include <QMouseEvent>
#include <QHeaderView>
Table_cell_resizer::Table_cell_resizer(QTableView* view) :
QObject(view), m_view(view)
{
m_view->viewport()->installEventFilter(this);
m_view->viewport()->setMouseTracking(true);
m_sensibility = 5;
m_drag_in_progress = false;
}
bool Table_cell_resizer::eventFilter(QObject* object, QEvent* event) {
if (object == m_view->viewport()) {
QMouseEvent* mouse_event = dynamic_cast<QMouseEvent*>(event);
if (mouse_event) {
if (mouse_event->type() == QEvent::MouseMove) {
if (m_drag_in_progress) { // apply dragging
int delta;
QHeaderView* header_view;
if (m_drag_orientation == Qt::Vertical) {
delta = mouse_event->pos().y() - m_drag_previous_pos;
header_view = m_view->verticalHeader();
m_drag_previous_pos = mouse_event->pos().y();
} else if (m_drag_orientation == Qt::Horizontal) {
delta = mouse_event->pos().x() - m_drag_previous_pos;
header_view = m_view->horizontalHeader();
m_drag_previous_pos = mouse_event->pos().x();
}
//using minimal size = m_sensibility * 2 to prevent collapsing
header_view->resizeSection(m_drag_section,
qMax(m_sensibility * 2, header_view->sectionSize(m_drag_section) + delta));
return true;
} else { // set mouse cursor shape
if (index_resizable(mouse_event->pos(), Qt::Vertical).isValid()) {
m_view->viewport()->setCursor(Qt::SplitVCursor);
} else if (index_resizable(mouse_event->pos(), Qt::Horizontal).isValid()) {
m_view->viewport()->setCursor(Qt::SplitHCursor);
} else {
m_view->viewport()->setCursor(QCursor());
}
}
} else if (mouse_event->type() == QEvent::MouseButtonPress &&
mouse_event->button() == Qt::LeftButton &&
!m_drag_in_progress) { // start dragging
if (index_resizable(mouse_event->pos(), Qt::Vertical).isValid()) {
m_drag_in_progress = true;
m_drag_orientation = Qt::Vertical;
m_drag_previous_pos = mouse_event->y();
m_drag_section = index_resizable(mouse_event->pos(), Qt::Vertical).row();
return true;
} else if (index_resizable(mouse_event->pos(), Qt::Horizontal).isValid()) {
m_drag_in_progress = true;
m_drag_orientation = Qt::Horizontal;
m_drag_previous_pos = mouse_event->x();
m_drag_section = index_resizable(mouse_event->pos(), Qt::Horizontal).column();
return true;
}
} else if (mouse_event->type() == QEvent::MouseButtonRelease &&
mouse_event->button() == Qt::LeftButton &&
m_drag_in_progress) { // stop dragging
m_drag_in_progress = false;
return true;
}
}
}
return false;
}
QModelIndex Table_cell_resizer::index_resizable(QPoint mouse_pos, Qt::Orientation orientation) {
QModelIndex index = m_view->indexAt(mouse_pos - QPoint(m_sensibility + 1, m_sensibility + 1));
if (index.isValid()) {
if (orientation == Qt::Horizontal) {
if (qAbs(m_view->visualRect(index).right() - mouse_pos.x()) < m_sensibility &&
m_view->horizontalHeader()->sectionResizeMode(index.column()) == QHeaderView::Interactive) {
return index;
}
} else {
if (qAbs(m_view->visualRect(index).bottom() - mouse_pos.y()) < m_sensibility &&
m_view->verticalHeader()->sectionResizeMode(index.row()) == QHeaderView::Interactive) {
return index;
}
}
}
return QModelIndex();
}
Usage:
new Table_cell_resizer(ui->table);
User can now resize rows and columns using cell area in addition to header areas. You can hide headers if you wish. This implementation respects header resize modes, so make sure that resize mode is set to QHeaderView::Interactive for headers which you want to be resizable. For example, you can set horizontal header mode to Interactive and vertical header mode to Fixed, resulting in resizable columns and fixed rows.

Qt: algorithm to rotate and resize a qgraphicslineitem present on a qgraphicsscene

Can someone please share the algorithm to rotate and resize a QGraphicsLineItem present on a QGraphicsScene? I wish to be able to click on either end of the line and rotate it while the opposite end automatically becomes the anchor point for rotation.
I have tried the solution given below and it works brilliantly!!. The solution is for line rotation only. This solution is provided to me when i posted the question at other Qt platform. All the credit goes to original author who provided the solution to me.
void Line::mousePressEvent( QGraphicsSceneMouseEvent * event ){
const QPointF pos = event->pos();
const qreal l1 = QLineF( pos, this->line().p1() ).length();
const qreal l2 = QLineF( pos, this->line().p2() ).length();
const qreal threshold = 3.5;
if( l1 < l2 and l1 < threshold ){
_dragIndex = 1;
} else if ( l2 < l1 and l2 < threshold ){
_dragIndex = 0;
} else{
_dragIndex = -1;
}
event->setAccepted( _dragIndex != -1 );
}
void Line::mouseMoveEvent( QGraphicsSceneMouseEvent * event ){
if( _dragIndex != -1 ){
const QPointF anchor = _dragIndex == 0 ? this->line().p1() : this->line().p2();
QLineF ma = QLineF(anchor,event->pos());
ma.setLength( line().length() );
const QPointF rotated = anchor + QPointF( ma.dx(), ma.dy() );
this->setLine( _dragIndex == 0 ? QLineF(anchor,rotated) : QLineF(rotated,anchor) );
}
}
void Line::mouseReleaseEvent( QGraphicsSceneMouseEvent * event ){
_dragIndex = -1;
QGraphicsLineItem::mouseReleaseEvent(event);
}
1- Overload mouseMoveEvent of your scene. Make sure you are in the initial state, no clicks, nothing. If position is close enough to the ends, set your flag as such.
// scene.cpp
void mouseMoveEvent(QMouseEvent *e){
if(moveToRotate){
lineItem->rotate(flag, e->pos());
...
return;
}
if(isClose(e->pos(), lineItem->firstEnd)
flag = 1;
else if(isClose(e->pos(), lineItem->secondEnd)
flag = 2;
else
flag = 0;
return;
}
2- Overload mouseClickEvent of the scene. If flag is set (1 or 2), get your anchor point. You can overload paint method of lineItem to highlight the end point. Also set firstClick flag.
void mouseClickEvent(QMouseEvent *e){ // firstClick happened
if(flag !=0){ //process click
firstClick = true;
paintAnchor = true;
moveToRotate = true;
}
else // neglect click
return;
return;
}
// myCustomLineItemclassThatInheritsQGraphicsLineItem.cpp
void paint(... ){
if(paintAnchor){
...
}
}
There are obvious errors, but the general flow should be as such. You may need a signal to connect the boolean to the paint event of another class. You may need to overload mouseReleaseEvent to properly set moveToRotate. And, of course rotate and isClose methods are yours to be written -maybe even exist in the API.
Just construct the main flowchart, it will help you a lot.

x11 limit mouse movements

I try to lock mouse cursor movements to the left half of the screen. I have following screen setup:
On the left side is a Qt window of size 1120x1080, on the right side a GL window of size 800x1080.
I use Openbox window manager under Ubuntu 12.10. The window layout stays fixed.
I need to restrict mouse movement to the Qt window.
To get the mouse to stay in the window, enable mouse movement with:
setMouseTracking(true);
and override void QWidget::mouseMovement( QMouseEvent * event )
void TheWindow::mouseMoveEvent ( QMouseEvent * event )
{
// get window size without frame
QRect s = geometry();
// get current cursor position
int x = event->globalX();
int y = event->globalY();
bool reset = false;
// Check cursor position relative to window
if (event->x() < 0)
{
x -= event->x();
reset = true;
}
else if (event->x() >= s.width())
{
x += s.width() - event->x() - 1;
reset = true;
}
if (event->y() < 0)
{
y -= event->y();
reset = true;
}
else if (event->y() >= s.height())
{
y += s.height() - event->y() - 1;
reset = true;
}
// if reset needed move cursor
if (reset) QCursor::setPos(x,y);
}
this involving QGraphicsItem::itemChange(). If you have an item which you want to restrict to a certain area then reimplement itemChange() for that item and monitor QGraphicsItem::ItemPositionHasChanged changes to see whether the items wants to be placed outside your area of interest and prevent that by returning a position from inside that area. for example:
QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
{
switch (change) {
case ItemPositionHasChanged:
if(x() < -200 || y() < -200 || x() > 200 || y() > 200)
setPos(0, 0);
graph->itemMoved();
break;
default:
break;
};
return QGraphicsItem::itemChange(change, value);
}

QSlider mouse direct jump

Instead of stepping when the user clicks somewhere on the qslider I want to make the slider jump to that position. How can this be implemented ?
after having problems with all versions of #spyke #Massimo Callegari and #Ben (slider position wasnt correct for the whole area) I found some Qt Style functionality within QSlider sourcecode: QStyle::SH_Slider_AbsoluteSetButtons.
You have to create a new QStyle which can be a very annoying, or you use ProxyStyle as shown by user jpn in http://www.qtcentre.org/threads/9208-QSlider-step-customize?p=49035#post49035
I've added another constructor and fixed a typo, but used the rest of the original source code.
#include <QProxyStyle>
class MyStyle : public QProxyStyle
{
public:
using QProxyStyle::QProxyStyle;
int styleHint(QStyle::StyleHint hint, const QStyleOption* option = 0, const QWidget* widget = 0, QStyleHintReturn* returnData = 0) const
{
if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
return (Qt::LeftButton | Qt::MidButton | Qt::RightButton);
return QProxyStyle::styleHint(hint, option, widget, returnData);
}
};
now you can set the style of your slider in the sliders constructor (if your slider is derived from QSlider):
setStyle(new MyStyle(this->style()));
or it should work this way if it is a standard QSlider:
standardSlider.setStyle(new MyStyle(standardSlider->style()));
so you use the original style of that element, but if the QStyle::SH_Slider_AbsoluteSetButtons "property" is asked you return as you want ;)
maybe you'll have to destroy these proxystyles on slider deletion, not tested yet.
Well, I doubt that Qt has a direct function for this purpose.
Try to use custom widgets. This should work!
Try the following logic
class MySlider : public QSlider
{
protected:
void mousePressEvent ( QMouseEvent * event )
{
if (event->button() == Qt::LeftButton)
{
if (orientation() == Qt::Vertical)
setValue(minimum() + ((maximum()-minimum()) * (height()-event->y())) / height() ) ;
else
setValue(minimum() + ((maximum()-minimum()) * event->x()) / width() ) ;
event->accept();
}
QSlider::mousePressEvent(event);
}
};
I needed this too and tried spyke solution, but it's missing two things:
inverted appearance
handle picking (when the mouse is over the handle, direct jump is not necessary)
So, here's the reviewed code:
void MySlider::mousePressEvent ( QMouseEvent * event )
{
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
if (event->button() == Qt::LeftButton &&
sr.contains(event->pos()) == false)
{
int newVal;
if (orientation() == Qt::Vertical)
newVal = minimum() + ((maximum()-minimum()) * (height()-event->y())) / height();
else
newVal = minimum() + ((maximum()-minimum()) * event->x()) / width();
if (invertedAppearance() == true)
setValue( maximum() - newVal );
else
setValue(newVal);
event->accept();
}
QSlider::mousePressEvent(event);
}
The answer of Massimo Callegari is almost right, but the calculation of newVal ignores the slider handle width. This problem comes up when you try to click near the end of the slider.
The following code fixes this for horizontal sliders
double halfHandleWidth = (0.5 * sr.width()) + 0.5; // Correct rounding
int adaptedPosX = event->x();
if ( adaptedPosX < halfHandleWidth )
adaptedPosX = halfHandleWidth;
if ( adaptedPosX > width() - halfHandleWidth )
adaptedPosX = width() - halfHandleWidth;
// get new dimensions accounting for slider handle width
double newWidth = (width() - halfHandleWidth) - halfHandleWidth;
double normalizedPosition = (adaptedPosX - halfHandleWidth) / newWidth ;
newVal = minimum() + ((maximum()-minimum()) * normalizedPosition);
Here is a simple implementation in python using QStyle.sliderValueFromPosition():
class JumpSlider(QtGui.QSlider):
def mousePressEvent(self, ev):
""" Jump to click position """
self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width()))
def mouseMoveEvent(self, ev):
""" Jump to pointer position while moving """
self.setValue(QtGui.QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width()))
The following code is actually a hack, but it works fine without sub-classing QSlider. The only thing you need to do is to connect QSlider valueChanged signal to your container.
Note1: You must set a pageStep > 0 in your slider
Note2: It works only for an horizontal, left-to-right slider (you should change the calculation of "sliderPosUnderMouse" to work with vertical orientation or inverted appearance)
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
// ...
connect(ui->mySlider, SIGNAL(valueChanged(int)),
this, SLOT(mySliderValueChanged(int)));
// ...
}
void MainWindow::mySliderValueChanged(int newPos)
{
// Make slider to follow the mouse directly and not by pageStep steps
Qt::MouseButtons btns = QApplication::mouseButtons();
QPoint localMousePos = ui->mySlider->mapFromGlobal(QCursor::pos());
bool clickOnSlider = (btns & Qt::LeftButton) &&
(localMousePos.x() >= 0 && localMousePos.y() >= 0 &&
localMousePos.x() < ui->mySlider->size().width() &&
localMousePos.y() < ui->mySlider->size().height());
if (clickOnSlider)
{
// Attention! The following works only for Horizontal, Left-to-right sliders
float posRatio = localMousePos.x() / (float )ui->mySlider->size().width();
int sliderRange = ui->mySlider->maximum() - ui->mySlider->minimum();
int sliderPosUnderMouse = ui->mySlider->minimum() + sliderRange * posRatio;
if (sliderPosUnderMouse != newPos)
{
ui->mySlider->setValue(sliderPosUnderMouse);
return;
}
}
// ...
}
My final implementation based on surrounding comments:
class ClickableSlider : public QSlider {
public:
ClickableSlider(QWidget *parent = 0) : QSlider(parent) {}
protected:
void ClickableSlider::mousePressEvent(QMouseEvent *event) {
QStyleOptionSlider opt;
initStyleOption(&opt);
QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this);
if (event->button() == Qt::LeftButton &&
!sr.contains(event->pos())) {
int newVal;
if (orientation() == Qt::Vertical) {
double halfHandleHeight = (0.5 * sr.height()) + 0.5;
int adaptedPosY = height() - event->y();
if ( adaptedPosY < halfHandleHeight )
adaptedPosY = halfHandleHeight;
if ( adaptedPosY > height() - halfHandleHeight )
adaptedPosY = height() - halfHandleHeight;
double newHeight = (height() - halfHandleHeight) - halfHandleHeight;
double normalizedPosition = (adaptedPosY - halfHandleHeight) / newHeight ;
newVal = minimum() + (maximum()-minimum()) * normalizedPosition;
} else {
double halfHandleWidth = (0.5 * sr.width()) + 0.5;
int adaptedPosX = event->x();
if ( adaptedPosX < halfHandleWidth )
adaptedPosX = halfHandleWidth;
if ( adaptedPosX > width() - halfHandleWidth )
adaptedPosX = width() - halfHandleWidth;
double newWidth = (width() - halfHandleWidth) - halfHandleWidth;
double normalizedPosition = (adaptedPosX - halfHandleWidth) / newWidth ;
newVal = minimum() + ((maximum()-minimum()) * normalizedPosition);
}
if (invertedAppearance())
setValue( maximum() - newVal );
else
setValue(newVal);
event->accept();
} else {
QSlider::mousePressEvent(event);
}
}
};
This modification to the JumpSlider above works in PyQt5:
class JumpSlider(QSlider):
def _FixPositionToInterval(self,ev):
""" Function to force the slider position to be on tick locations """
# Get the value from the slider
Value=QStyle.sliderValueFromPosition(self.minimum(), self.maximum(), ev.x(), self.width())
# Get the desired tick interval from the slider
TickInterval=self.tickInterval()
# Convert the value to be only at the tick interval locations
Value=round(Value/TickInterval)*TickInterval
# Set the position of the slider based on the interval position
self.setValue(Value)
def mousePressEvent(self, ev):
self._FixPositionToInterval(ev)
def mouseMoveEvent(self, ev):
self._FixPositionToInterval(ev)
I think,
the QStyle::sliderValueFromPosition() function can be used.
http://qt-project.org/doc/qt-5/qstyle.html#sliderValueFromPosition
i have been trying and searching this on net and was expecting Qt for a smarter way doing this, unfortunately there was not big help (may be i was not searching properly )
well i have done this in Qt creator:
Add an eventFilter in header ( takes QObject and QEvent as argument ) (bool return type)
Initialize in constructor ..for eg .. if ur slider is HSlider then
ui->HSlider->installEventFilter(this);
In the defination :
a. check if the object is your slider type something like : ui->HSlider == Object
b. Check for mouse click event something like : QEvent::MouseButtonPress == event->type
c. if the above all passes means u have got mouse event on the slider do something like : in definition : ui->HSlider->setValue( Qcursor::pos().x() - firstval ); return QMainWindow::eventFilter(object, event);
Note: fistVal : can be taken out by printing the cursur position at 0 = initial position of the slider ( with help of QCursor::pos().x() )
hope this helps
A simple method would be to derive from QSlider and reimplement mousePressEvent(....) to set the marker position using setSliderPosition(int).
I also met this problem. My solution is shown below.
slider->installEventFilter(this);
---
bool MyDialog::eventFilter(QObject *object, QEvent *event)
{
if (object == slider && slider->isEnabled())
{
if (event->type() == QEvent::MouseButtonPress)
{
auto mevent = static_cast<QMouseEvent *>(event);
qreal value = slider->minimum() + (slider->maximum() - slider->minimum()) * mevent->localPos().x() / slider->width();
if (mevent->button() == Qt::LeftButton)
{
slider->setValue(qRound(value));
}
event->accept();
return true;
}
if (event->type() == QEvent::MouseMove)
{
auto mevent = static_cast<QMouseEvent *>(event);
qreal value = slider->minimum() + (slider->maximum() - slider->minimum()) * mevent->localPos().x() / slider->width();
if (mevent->buttons() & Qt::LeftButton)
{
slider->setValue(qRound(value));
}
event->accept();
return true;
}
if (event->type() == QEvent::MouseButtonDblClick)
{
event->accept();
return true;
}
}
return QDialog::eventFilter(object, event);
}
You can also override these event handlers of QSlider.
QSlider::mousePressedEvent
QSlider::mouseMoveEvent
QSlider::mouseDoubleClickEvent

Why does the x value change in this program?

I have created this code, and when I run it, don't get any errors until the arrow leaves the screen (ie: (*I)->x>maxx), after which the O will randomly teleport (Well, I'm guessing its not random, but I'm trying to find a pattern to it).
EDIT: the random teleportation don't seem to occur if I move up, and if I move down, the O is teleported directly to the bottom. Also, a glitch has occured where the O becomes a '>'. (I am trying to figure out how that happens)
EDIT: the transform-into-'>' glitch occurs if the O is at the bottom right of the screen (player.x=9;player.y=9) and the sequence "wqs" is entered.
EDIT: I've removed the class declarations because I am fairly sure that the error is within the _move()s and check().
EDIT: The transform glitch appears to occur when 'wq' is typed, then any other character is entered (ie "skiping" the next move)
EDIT: The tranform glitch occurs when player.x=9; player.y=8; and then 'q' is pressed, the next move the player tranforms into a '>'
This is the code:
#include<vector>
#include<iostream>
#include<string>
using namespace std;
const int maxx = 10, maxy = 10; //two constants that show the size of the sector
char sector[maxx][maxy]; //array of characters used to display the sector
prgm player(0, 0, 'O'); //player definition at x0,y0,and displayed with 'O'
const int vsize = 1; //size of the enemy array (ie: how many enemies there will be
X1 a(9, 5, 'X', 10); //enemy "a", has a move function that moves it back and forth
virus * viral_data[vsize] = {&a}; //array of enemies used to set the sector
vector<antivirus*> antiviral_data; //vector of pointers to "antivirus" the weapon used
vector<antivirus*>::iterator I; //iterator for previous vector
void display() //function to display the sector
{
for(int i = 0; i < maxy; i++)
{
for(int j = 0; j < maxx; j++)
{
cout<<sector[j][i];
}
cout<<endl;
}
return;
}
void p_move() //function to get players input, then move the player or create "antivirus"
{
char dir;
cin>>dir;
switch(dir)
{
case 'w':
player.y--;
break;
case 'a':
player.x--;
break;
case 's':
player.y++;
break;
case 'd':
player.x++;
break;
case 'q':
antiviral_data.push_back(new aX1(player.x, player.y, '>')); //creates a new aX1 at the players position
break;
}
return;
}
void v_move() //uses the enemies move
{
for(int i = 0; i < vsize; i++)
{
viral_data[i]->move();
}
return;
}
void a_move() //uses the weapon (ie: moves the weapon forward)
{
for(I = antiviral_data.begin(); I < antiviral_data.end(); I++)
{
(*I)->move();
}
return;
}
void set() //sets the sector array (char)
{
for(int i = 0; i < maxy; i++)
{
for(int j = 0; j < maxx; j++)
{
sector[j][i] = ' '; makes the entire sector blank
}
}
sector[player.x][player.y]=player.sym; //sets the sector at the player's position to 'O'
for(int i = 0; i < vsize; i++)
{
sector[viral_data[i]->x][viral_data[i]->y] = viral_data[i]->sym; //sets the sector at each enemy's position to be 'X'
}
for(I = antiviral_data.begin(); I < antiviral_data.end(); I++)
{
sector[(*I)->x][(*I)->y] = (*I)->sym; //sets the sector at each weapon's position to be '>'
}
return;
}
void check() //prevents the player from moving off the screen, erases bullet if it moves of the screen (to prevent access to non-allocated memory)
{
if(player.x < 0)
{
player.x = 0;
}
if(player.y < 0)
{
player.y = 0;
}
if(player.x > (maxx-1))
{
player.x = (maxx-1);
}
if(player.y > (maxy-1))
{
player.y = (maxy-1);
}
//PROBLEM APPEARS TO OCCUR HERE
for(I = antiviral_data.begin(); I! = antiviral_data.end();)
{
if((*I)->x > maxx)
{
I = antiviral_data.erase(I);
}
else
{
I++;
}
}
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
return;
}
int main()
{
while(true)
{
set(); //set sector
display(); //display sector
p_move(); //player's move
v_move(); //enemy's move
a_move(); //bullet's move
check();//check moves
}
return 0;
}
In check(), the test
((*I)->x > maxx)
should be
((*I)->x >= maxx)
. This is an off-by-one error that lets the > get one square off the screen. When the display routine tries to display it, it clobbers the display symbol for the X.

Resources