I have to merge the rows of excel using spreadsheet gear controls is it possible. Only specific rows of single column
All detail is being included in this screencast
The changes that has been done by me is
DataTable dt = (DataTable)ViewState["dtGrid"]
System.Random rd = new System.Random(DateTime.Now.Millisecond);
int MyValue = rd.Next(1000000, 99999999);
sUniqueName = MyValue.ToString();
// Create a new workbook.
SpreadsheetGear.IWorkbook workbook = SpreadsheetGear.Factory.GetWorkbook();
SpreadsheetGear.IRange cells = workbook.Worksheets[0].Cells;
cells.CopyFromDataTable(dt, SpreadsheetGear.Data.SetDataFlags.None);
cells.Rows[0, 0, 0, 51].Interior.Color = System.Drawing.Color.Navy;
cells.Rows[0, 0, 0, 51].Font.Color = System.Drawing.Color.White;
cells["A:R"].Columns.AutoFit();
string filename = string.Format("{0}-{1}-{2}", "AOMIndoorInventoryReport", DateTime.Now.ToString("MM-dd-yy"), sUniqueName);
Response.Clear();
Response.ContentType = "application/vnd.ms-excel";
Response.AddHeader("Content-Disposition", "attachment; filename=" + filename + ".xls");
workbook.SaveToStream(Response.OutputStream, SpreadsheetGear.FileFormat.Excel8);
Response.End();
What should be added?
You can merge cells by calling IRange.Merge() on the desired cells. Example:
cells["A7:A8"].Merge();
cells[8, 0, 22, 0].Merge();
UPDATE:
You've asked how to dynamically merge a range of cells based on adjacent rows in a column which have the same value. To accomplish this would require looping through each row in this column and comparing each cell's value with the previous value, merging when appropriate as you go down the column.
I am providing some sample code below which demonstrates one way in which you might go about this (there are certainly many other ways). I had to make some assumptions about your underlying data and requirements, so some modification on your end might be needed. Note the use of some handy methods under the IRange interface (see the IRange.Intersect(...) / Subtract(...) / Union(...) methods) which allow you to "interact" two IRanges to create a new third IRange.
...
// Create a new workbook and some local variables for convenience.
SpreadsheetGear.IWorkbook workbook = SpreadsheetGear.Factory.GetWorkbook();
SpreadsheetGear.IWorksheet worksheet = workbook.Worksheets[0];
SpreadsheetGear.IRange cells = worksheet.Cells;
// Copy data from DataTable to worksheet
cells.CopyFromDataTable(dt, SpreadsheetGear.Data.SetDataFlags.None);
// Here I am creating an IRange representing the used part of column a and without
// the header row, which I presume is in Row 1, and should not be included in this
// merging routine.
SpreadsheetGear.IRange usedColA = worksheet.UsedRange.Intersect(
cells["A:A"]).Subtract(cells["1:1"]);
// No point in attempting to merge cells if there's only a single row.
if (usedColA.RowCount > 1)
{
// Some variables to keep track of the content of the "current" and "previous"
// cells as we loop through "usedColA".
string prevCellVal = "";
string curCellVal = "";
// We'll use this variable to keep track of ranges which will need to be merged
// during the routine. Here I seed "mergeRange" with the first cell in usedColA.
SpreadsheetGear.IRange mergeRange = usedColA[0, 0];
// Loop through each cell in the used part of Column A.
foreach (SpreadsheetGear.IRange cell in usedColA)
{
// Get text of current "cell".
curCellVal = cell.Text;
// Your screenshot seems to indicate that you don't care about merging empty
// cells so this routine takes this into account. Either an empty cell or
// mismatched text from the "current" and "previous" cell indicate we should
// merge whatever cells we've accumulated in "mergeRange" and then reset this
// range to look for more ranges to merge further down the column.
if (curCellVal.Length == 0 || curCellVal != prevCellVal)
{
// Only merge if this range consists of more than 1 cell.
if (mergeRange.CellCount > 1)
mergeRange.Merge();
// Reset merged range to the "current" cell.
mergeRange = cell;
prevCellVal = curCellVal;
}
// If the current and previous cells contain the same text, add this "cell"
// to the "mergeRange". Note the use of IRange.Union(...) to combine two
// IRange objects into one.
else if (curCellVal == prevCellVal)
mergeRange = mergeRange.Union(cell);
}
// One last check for any cells to merge at the very end of the column.
if (mergeRange.CellCount > 1)
mergeRange.Merge();
}
...
Related
I have a problem, i want to return the selected Rows values, and the columns separately, i found a method to return both of them using the function cell(row, column), but i want to get them separately
Here is my code :
QTableWidgetItem *c = new QTableWidgetItem();
QMap<QString,int> lists;
for(i=0;i<range.rowCount();++i){
for(int j=0;j<range.columnCount();++j){
c=item(i,j);// here i can return the Rows, Columns Data
QMessageBox::information(this,"",c->text());
}
}
As you can see this code is working, but i just want to return the Rows and the Columns separately so i can put them in my QMap<QString,int> list.
And the purpose of all this is to try to draw a piechart from the selected rows and columns
So Any help please
Here is what I understood from the comments, feel free to correct me and I'll update my answer if necessary.
COL1 | COL2
NAME | VALUE
So when you select a cell, you actually care about the whole row, a.k.a the name of the row and the value associated. If this is the case, it would make more sense to only allow the user to select whole rows, instead of cells. setSelectionBehavior(QAbstractItemView::SelectRows); should do the trick.
Provided that the name of the dataset is always in column 1, and the value in column 2, you should update your code with the snippet:
QTableWidgetItem *c; //Deleted memory leak in your code.
QMap<QString,double> myMap; //Don't name it a list if it is explicitly a map.
for(i=0;i<range.rowCount();++i){
QString dataName = item(i,0)->text();
int dataValue;
for(int j=1;j<range.columnCount();++j){
c=item(i,j);// here i can return the Rows, Columns Data
dataValue += c->text().toDouble();
//If you always have 2 columns only, dataValue will be the value you are looking for.
//If you can have more than 2 columns, dataValue will be the sum of all the cells located after the column 0, on the same row.
//Change this depending on how you want to treat those values.
QMessageBox::information(this,dataName,c->text());
}
myMap[dataName]=dataValue;
}
EDIT for QPieSeries, following this example:
QPieSeries *series = new QPieSeries();
QMap<QString,double>::iterator it = myMap.begin();
QMap<QString,double>::iterator end = myMap.end();
for(; it!=end; ++it){
series->append(it->key(), it->value());
}
QPieSlice *slice = series->slices().at(1);
slice->setExploded();
slice->setLabelVisible();
slice->setPen(QPen(Qt::darkGreen, 2));
slice->setBrush(Qt::green);
QChart *chart = new QChart();
chart->addSeries(series);
chart->setTitle("My Data");
chart->legend()->hide();
QChartView *chartView = new QChartView(chart);
chartView->setRenderHint(QPainter::Antialiasing);
/*change with your window here*/
yourWindow.setCentralWidget(chartView);
i am new to PHPExcel learning from last two days and i am generating one report for the form input data. I have generated dynamically columns in the excel report but not able to set the first column as Index & last column as Date.
My code is:
// setting column names begin
$col = 1;
$row = 0;
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow(0, $row, "Index No.");
foreach ($formInfo['fields'] as $fields) {
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col, $row, $fields['grid-name']);
$col++;
}
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($col, $row, 'Date & Time of Input');
// setting column names ends!
Thanks in advance for response.
You have achieved the most. I just updated your code. Now it will work like as per you wish.
// Initializing last col variable
$endcolval = 0;
// Storing the value to First Column
$objPHPExcel->setActiveSheetIndex(0)
->setCellValueByColumnAndRow(0, 1, "Index");
// Storing the rest of the values from array to the respect indexes
foreach ($formInfo['fields'] as $col=>$fields)
{
$objPHPExcel->setActiveSheetIndex(0)
->setCellValueByColumnAndRow($col+1, 1, $fields['grid-name']);
// Using the above function you can able dynamically store the values to the cell.
// setCellValueByColumnAndRow(Column_Number, Row_Number, Value_To_Save);
$endcolval = $col+1;// Getting the last column number
}
// Assigning the Date to the Last Column.
$objPHPExcel->setActiveSheetIndex(0)
->setCellValueByColumnAndRow($endcolval+1, 1, "Date");
This pertains to .NET Web Performance Tests.
If I have an ASP.NET page with a GridView that has a column of ints, how do I write an extraction rule to get the largest int in the column?
I tried creating a custom extraction rule by inheriting from ExtractionRule and in the Extract method using e.Response.HtmlDocument.GetFilteredHtmlTags however, the HtmlTags returned don't seem to expose their innerHtml contents.
Perhaps you can write an extraction rule that gets the whole column, then process the numbers to get their maximum value. Alternatively, use a built-in extraction rule to get the whole column, then write a plugin to get the maximum value. In either case your code should expect a mixture of numbers and other text.
Ben Day has a great blog post containing two types that express similar concerns. TableColumnValueValidator and ExtractRandomValueFromTable.
http://www.benday.com/2013/08/19/validation-extraction-rules-for-visual-studio-2012-web-performance-tests/
In the Extract(object, ExtractionEventArgs), you need to parse the ExtractionEventArgs.Response.BodyString. Ben uses the HtmlAgilityPack library for this. http://www.nuget.org/packages/htmlagilitypack
Something like this is roughly the code you'd need. This is simliar logic to ExtractRandomValueFromTable.
This does not account for thead/tbody or cells that span multiple columns/rows.
HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(e.Response.BodyString);
HtmlNode table = doc.GetElementbyId(TableId); // TableId is a test property
HtmlNodeCollection columns = table.SelectNodes("//th");
int columnIndex = FindColumnIndexByName(columns, ColumnName); // ColumnName is a test property
HtmlNodeCollection rows = table.SelectNodes("//tr")
int maxValue = Int32.MinValue;
foreach(HtmlNode row in rows)
{
HtmlNodeCollection cells = row.SelectNodes("./td");
// Todo check for bounds of cells here
HtmlNode cell = cells[columnIndex];
int value = Int32.MinValue;
Int32.TryParse(cell.InnerText.Trim(), out value);
maxValue = Math.Max(value, maxValue);
}
e.WebTest.Context.Add(ContextParameterName, maxValue);
int FindColumnIndexByName(HtmlNodeCollection columns, string columnName)
{
for(int i=0; i<columns.Count; i++)
if (String.Equals(columns[i].InnerText, columnName, StringComparison.OrdinalIgnoreCase))
{
return i;
}
return -1;
}
I need to check if the user has entered a valid number in a cells A1:A10. In Excel i would choose the cells and then create a custom validator and set the formula to =isNumber("$A$1:$A10")
Trying do this using POI is getting me all tied in knots:
Here is what i have tried:
CellRangeAddressList addressList = new CellRangeAddressList(0, 10, 0, 0);
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
DataValidationConstraint customConstraint = dvHelper.createCustomConstraint("isNumber(\"$A$0:$A$10\"");
XSSFDataValidation validation = (XSSFDataValidation)dvHelper.createValidation(customConstraint, addressList);
validation.setShowErrorBox(true);
sheet.addValidationData(validation);
When i try and open this in Excel, i get an error and Excel disables the validation
thanks in advance
-anish
CellReference crStartCell = new CellReference(startRow, column, true, true); // 0-based row and column index
CellReference crEndCell = new CellReference(endRow, column, true, true);
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint) dvHelper.createCustomConstraint("ISNUMBER("+crStartCell.formatAsString()+":"+crEndCell.formatAsString() +")");
You can convert that excel to csv than perform your validations using SuperCSV. It would be length but more easier.
I have a text file that contains around 21 lac entries and I want to insert all these entries into a table. Initially I have created one function in c# that read line by line and insert into table but it takes too much time. Please suggest an efficient way to insert these bulk data and that file is containing TAB(4 spaces) as delimiter.
And that text file also containing some duplicate entries and I don't want to insert those entries.
Load all of your data into a DataTable object and then use SqlBulkCopy to bulk insert them:
DataTable dtData = new DataTable("Data");
// load your data here
using (SqlConnection dbConn = new SqlConnection("db conn string"))
{
dbConn.Open();
using (SqlTransaction dbTrans = dbConn.BeginTransaction())
{
try
{
using (SqlBulkCopy dbBulkCopy = new SqlBulkCopy(dbConn, SqlBulkCopyOptions.Default, dbTrans))
{
dbBulkCopy.DestinationTableName = "intended SQL table name";
dbBulkCopy.WriteToServer(dtData );
}
dbTrans.Commit();
}
catch
{
dbTrans.Rollback();
throw;
}
}
dbConn.Close();
}
I've included the example to wrap this into a SqlTransaction so there will be a full rollback if there's a failure along the way. To get you started, here's a good CodeProject article on loading the delimited data into a DataSet object.
Sanitizing the data before loading
OK, here's how I think your data looks:
CC_FIPS FULL_NAME_ND
AN Xixerella
AN Vila
AN Sornas
AN Soldeu
AN Sispony
... (cut down for brevity)
In this instance you want to create your DataTable like this:
DataTable dtData = new DataTable("Data");
dtData.Columns.Add("CC_FIPS");
dtData.Columns.Add("FULL_NAME_ND");
Then you want to iterate each row (assuming your tab delimited data is separated row-by-row by carriage returns) and check whether this data already exists in the DataTable using the .Select method and if there is a match (i'm checking for BOTH values, it's up to you whether you want to do something else) then don't add it thereby preventing duplicates.
using (FileStream fs = new FileStream("path to your file", FileMode.Open, FileAccess.Read))
{
int rowIndex = 0;
using (StreamReader sr = new StreamReader(fs))
{
string line = string.Empty;
while (!sr.EndOfStream)
{
line = sr.ReadLine();
// use a row index to skip the header row as you don't want to insert CC_FIPS and FULL_NAME_ND
if (rowIndex > 0)
{
// split your data up into a 2-d array tab delimited
string[] parts = line.Split('\t');
// now check whether this data has already been added to the datatable
DataRow[] rows = dtData.Select("CC_FIPS = '" + parts[0] + "' and FULL_NAME_ND = '" + parts[1] + "'");
if (rows.Length == 0)
{
// if there're no rows, then the data doesn't exist so add it
DataRow nr = dtData.NewRow();
nr["CC_FIPS"] = parts[0];
nr["FULL_NAME_ND"] = parts[1];
dtData.Rows.Add(nr);
}
}
rowIndex++;
}
}
}
At the end of this you should have a sanitized DataTable that you can bulk insert. Please note that this code isn't tested, but it's a best guess as to how you should do it. There are many ways this can be done, and probably a lot better than this method (specifically LINQ) - but it's a starting point.