sorry I ask a lot of questions in this forum because I am really a beginner. So I have a body temperature and oxygen saturation monitoring tool project. I'm using nodemcu esp8266, sensor ds18b20, and sensor max30100. the configuration between the three tools has been successful, but when entering a coding program to send data to google firebase the oxygen saturation value cannot retrieve data repeatedly, for example as shown below. enter image description here
This my code :
//ESP8266 Based Patient Health Monitoring System
#include <ESP8266WebServer.h>
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <OneWire.h>
#include <DallasTemperature.h>
#include <FirebaseArduino.h>
#define FIREBASE_HOST "monitoring-oximeter-d2ff2-default-rtdb.firebaseio.com"
#define FIREBASE_AUTH "uxoi7mv66IxOBG5ZoGBJY51hPp0AfbYezmmeCkvu"
#define DS18B20 2 //D4 pin= GPIO pin 2
#define REPORTING_PERIOD_MS 1000
int BPM, SpO2, bodytemperature;
/*Put your SSID & Password*/
const char* ssid = "HAURA"; // Enter SSID here
const char* password = "13131313"; //Enter Password here
PulseOximeter pox;
uint32_t tsLastReport = 0;
OneWire oneWire(DS18B20);
DallasTemperature sensors(&oneWire);
ESP8266WebServer server(80);
int g;
//-----------------
void onBeatDetected()
{
;
}
void setup() {
lcd.begin(16,2);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.print("Digital Oximeter");
lcd.setCursor(0, 1);
lcd.print("Tunggu Koneksi..");
delay(1000);
if (!pox.begin()) {
lcd.setCursor(0, 1);
lcd.print("Koneksi Gagal ");
for(;;);
} else {
;
}
pox.setIRLedCurrent(MAX30100_LED_CURR_24MA);
pox.setOnBeatDetectedCallback(onBeatDetected);
lcd.clear();
lcd.print("SpO2= %");
lcd.setCursor(0, 1);
lcd.print("PR = BPM");
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Serial.begin(115200);
pinMode(16, OUTPUT);
delay(100);
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
Serial.print("Initializing pulse oximeter..");
if (!pox.begin()) {
Serial.println("FAILED");
for (;;);
} else {
Serial.println("SUCCESS");
}
}
void loop() {
server.handleClient();
pox.update();
sensors.requestTemperatures();
g++;
if(g>5000){
g=0;
BPM = pox.getHeartRate();
SpO2 = pox.getSpO2();
bodytemperature = sensors.getTempCByIndex(0);
if((BPM<101)&&(SpO2<101)&&(bodytemperature<101)){
lcd.setCursor(5, 0);
lcd.print(SpO2);
lcd.print(" ");
lcd.setCursor(5, 1);
lcd.print(BPM);
lcd.print(" ");
}
}
Firebase.setInt("BPM", BPM);
if (Firebase.failed()) {
Serial.print("pushing /logs failed:");
Serial.println(Firebase.error());
return;
}
Firebase.setInt("SpO2", SpO2);
if (Firebase.failed()) {
Serial.print("pushing /logs failed:");
Serial.println(Firebase.error());
return;
}
Firebase.setInt("bodytemperature", bodytemperature);
if (Firebase.failed()) {
Serial.print("pushing /logs failed:");
Serial.println(Firebase.error());
return;
}
if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
bodytemperature = sensors.getTempCByIndex(0);
BPM = pox.getHeartRate();
SpO2 = pox.getSpO2();
Serial.print("BPM: ");
Serial.println(BPM);
Serial.print("SpO2: ");
Serial.print(SpO2);
Serial.println("%");
Serial.print("Body Temperature: ");
Serial.print(bodytemperature);
Serial.println("°C");
Serial.println("*********************************");
Serial.println();
tsLastReport = millis();
}
}
void handle_OnConnect() {
server.send(200, "text/html", SendHTML(BPM, SpO2, bodytemperature));
}
void handle_NotFound() {
server.send(404, "text/plain", "Not found");
}
String SendHTML(float BPM, float SpO2, float bodytemperature) {
String html = "<!DOCTYPE html>";
html += "<html>";
html += "<head>";
html += "<title>Patient Health Monitoring</title>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
html += "<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.2/css/all.min.css'>";
html += "<link rel='stylesheet' type='text/css' href='styles.css'>";
html += "<style>";
html += "body { background-color: #fff; font-family: sans-serif; color: #333333; font: 14px Helvetica, sans-serif box-sizing: border-box;}";
html += "#page { margin: 20px; background-color: #fff;}";
html += ".container { height: inherit; padding-bottom: 20px;}";
html += ".header { padding: 20px;}";
html += ".header h1 { padding-bottom: 0.3em; color: #008080; font-size: 45px; font-weight: bold; font-family: Garmond, 'sans-serif'; text-align: center;}";
html += "h2 { padding-bottom: 0.2em; border-bottom: 1px solid #eee; margin: 2px; text-align: left;}";
html += ".header h3 { font-weight: bold; font-family: Arial, 'sans-serif'; font-size: 17px; color: #b6b6b6; text-align: center;}";
html += ".box-full { padding: 20px; border 1px solid #ddd; border-radius: 1em 1em 1em 1em; box-shadow: 1px 7px 7px 1px rgba(0,0,0,0.4); background: #fff; margin: 20px; width: 300px;}";
html += "#media (max-width: 494px) { #page { width: inherit; margin: 5px auto; } #content { padding: 1px;} .box-full { margin: 8px 8px 12px 8px; padding: 10px; width: inherit;; float: none; } }";
html += "#media (min-width: 494px) and (max-width: 980px) { #page { width: 465px; margin 0 auto; } .box-full { width: 380px; } }";
html += "#media (min-width: 980px) { #page { width: 930px; margin: auto; } }";
html += ".sensor { margin: 12px 0px; font-size: 2.5rem;}";
html += ".sensor-labels { font-size: 1rem; vertical-align: middle; padding-bottom: 15px;}";
html += ".units { font-size: 1.2rem;}";
html += "hr { height: 1px; color: #eee; background-color: #eee; border: none;}";
html += "</style>";
//Ajax Code Start
html += "<script>\n";
html += "setInterval(loadDoc,1000);\n";
html += "function loadDoc() {\n";
html += "var xhttp = new XMLHttpRequest();\n";
html += "xhttp.onreadystatechange = function() {\n";
html += "if (this.readyState == 4 && this.status == 200) {\n";
html += "document.body.innerHTML =this.responseText}\n";
html += "};\n";
html += "xhttp.open(\"GET\", \"/\", true);\n";
html += "xhttp.send();\n";
html += "}\n";
html += "</script>\n";
//Ajax Code END
html += "</head>";
html += "<body>";
html += "<div id='page'>";
html += "<div class='header'>";
html += "<h1>Health Monitoring System</h1>";
html += "</div>";
html += "<div id='content' align='center'>";
html += "<div class='box-full' align='left'>";
html += "<h2>Sensors Readings</h2>";
html += "<div class='sensors-container'>";
//For Heart Rate
html += "<p class='sensor'>";
html += "<i class='fas fa-heartbeat' style='color:#cc3300'></i>";
html += "<span class='sensor-labels'> Heart Rate </span>";
html += (int)BPM;
html += "<sup class='units'>BPM</sup>";
html += "</p>";
html += "<hr>";
//For Sp02
html += "<p class='sensor'>";
html += "<i class='fas fa-burn' style='color:#f7347a'></i>";
html += "<span class='sensor-labels'> Sp02 </span>";
html += (int)SpO2;
html += "<sup class='units'>%</sup>";
html += "</p>";
html += "<hr>";
//For Body Temperature
html += "<p class='sensor'>";
html += "<i class='fas fa-thermometer-full' style='color:#d9534f'></i>";
html += "<span class='sensor-labels'> Body Temperature </span>";
html += (int)bodytemperature;
html += "<sup class='units'>°C</sup>";
html += "</p>";
html += "</div>";
html += "</div>";
html += "</div>";
html += "</div>";
html += "</div>";
html += "</body>";
html += "</html>";
return html;
}
Related
I have been working on the following project that was created by Rui Santos and wanted to make some modifications.
ESP32 Web Server Slider
In the code the frequency is set constant and the duty cycle is adjustable with a slider. I would like to add a slide that also adjusts the frequency from 100Hz to 10kHz.
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-web-server-slider-pwm/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
const int output = 2;
String sliderValue = "0";
// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
const char* PARAM_INPUT = "value";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP Web Server</title>
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 2.3rem;}
p {font-size: 1.9rem;}
body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
.slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #FFD65C;
outline: none; -webkit-transition: .2s; transition: opacity .2s;}
.slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background: #003249; cursor: pointer;}
.slider::-moz-range-thumb { width: 35px; height: 35px; background: #003249; cursor: pointer; }
</style>
</head>
<body>
<h2>ESP Web Server</h2>
<p><span id="textSliderValue">%SLIDERVALUE%</span></p>
<p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="255" value="%SLIDERVALUE%" step="1" class="slider"></p>
<script>
function updateSliderPWM(element) {
var sliderValue = document.getElementById("pwmSlider").value;
document.getElementById("textSliderValue").innerHTML = sliderValue;
console.log(sliderValue);
var xhr = new XMLHttpRequest();
xhr.open("GET", "/slider?value="+sliderValue, true);
xhr.send();
}
</script>
</body>
</html>
)rawliteral";
// Replaces placeholder with button section in your web page
String processor(const String& var){
//Serial.println(var);
if (var == "SLIDERVALUE"){
return sliderValue;
}
return String();
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
// configure LED PWM functionalitites
ledcSetup(ledChannel, freq, resolution);
// attach the channel to the GPIO to be controlled
ledcAttachPin(output, ledChannel);
ledcWrite(ledChannel, sliderValue.toInt());
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
// Print ESP Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Send a GET request to <ESP_IP>/slider?value=<inputMessage>
server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
// GET input1 value on <ESP_IP>/slider?value=<inputMessage>
if (request->hasParam(PARAM_INPUT)) {
inputMessage = request->getParam(PARAM_INPUT)->value();
sliderValue = inputMessage;
ledcWrite(ledChannel, sliderValue.toInt());
}
else {
inputMessage = "No message sent";
}
Serial.println(inputMessage);
request->send(200, "text/plain", "OK");
});
// Start server
server.begin();
}
void loop() {
}
It seems the Arduino interface to ESP32 PWM is not really documented, but if you look at the relevant header and source then you'll find a function ledcChangeFrequency() which seems to do the trick.
const double newFreq = ledcChangeFrequency(ledChannel, freq, resolution);
serial.println(newFreq);
/*********
Rui Santos
Complete project details at https://RandomNerdTutorials.com/esp32-web-server-slider-pwm/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*********/
// Import required libraries
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
const int output = 2;
String sliderValue = "0";
// setting PWM properties
const int freq = 5000;
const int ledChannel = 0;
const int resolution = 8;
const char* PARAM_INPUT = "value";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ESP Web Server</title>
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 2.3rem;}
p {font-size: 1.9rem;}
body {max-width: 400px; margin:0px auto; padding-bottom: 25px;}
.slider { -webkit-appearance: none; margin: 14px; width: 360px; height: 25px; background: #FFD65C;
outline: none; -webkit-transition: .2s; transition: opacity .2s;}
.slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 35px; height: 35px; background: #003249; cursor: pointer;}
.slider::-moz-range-thumb { width: 35px; height: 35px; background: #003249; cursor: pointer; }
</style>
</head>
<body>
<h2>ESP Web Server</h2>
<p><span id="textSliderValue">%SLIDERVALUE%</span></p>
<p><input type="range" onchange="updateSliderPWM(this)" id="pwmSlider" min="0" max="255" value="%SLIDERVALUE%" step="1" class="slider"></p>
<p><span id="textSliderValue2">%SLIDERFREQ</span></p>
<p><input type="range" onchange="updateSliderFREQ(this)" id="freqSlider" min="0" max="255" value="%SLIDERVALUE%" step="1" class="slider"></p>
<script>
function updateSliderPWM(element) {
var sliderValue = document.getElementById("pwmSlider").value;
document.getElementById("textSliderValue").innerHTML = sliderValue;
console.log(sliderValue);
var xhr = new XMLHttpRequest();
xhr.open("GET", "/slider?value="+sliderValue, true);
xhr.send();
}
function updateSliderFREQ(element) {
var sliderValue = document.getElementById("freqSlider").value;
document.getElementById("textSliderValue2").innerHTML = sliderValue;
console.log(sliderValue);
var xhr = new XMLHttpRequest();
xhr.open("GET", "/freq?value="+sliderValue, true);
xhr.send();
}
</script>
</body>
</html>
)rawliteral";
// Replaces placeholder with button section in your web page
String processor(const String& var){
//Serial.println(var);
if (var == "SLIDERVALUE"){
return sliderValue;
}
return String();
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
// configure LED PWM functionalitites
ledcSetup(ledChannel, freq, resolution);
// attach the channel to the GPIO to be controlled
ledcAttachPin(output, ledChannel);
ledcWrite(ledChannel, sliderValue.toInt());
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
// Print ESP Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
// Send a GET request to <ESP_IP>/slider?value=<inputMessage>
server.on("/slider", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
// GET input1 value on <ESP_IP>/slider?value=<inputMessage>
if (request->hasParam(PARAM_INPUT)) {
inputMessage = request->getParam(PARAM_INPUT)->value();
sliderValue = inputMessage;
ledcWrite(ledChannel, sliderValue.toInt());
}
else {
inputMessage = "No message sent";
}
Serial.println(inputMessage);
request->send(200, "text/plain", "OK");
});
server.on("/freq", HTTP_GET, [] (AsyncWebServerRequest *request) {
String inputMessage;
// GET input1 value on <ESP_IP>/slider?value=<inputMessage>
if (request->hasParam(PARAM_INPUT)) {
inputMessage = request->getParam(PARAM_INPUT)->value();
sliderValue = inputMessage;
freq = sliderValue.toInt();
}
else {
inputMessage = "No message sent";
}
Serial.println(inputMessage);
request->send(200, "text/plain", "OK");
});
// Start server
server.begin();
}
void loop() {
}
GtkCssProvider *provider;
GdkDisplay *display;
GdkScreen *screen;
provider = gtk_css_provider_new ();
display = gdk_display_get_default ();
screen = gdk_display_get_default_screen (display);
gtk_style_context_add_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
const gchar *myCssFile = "style.css";
GError *error = 0;
gtk_css_provider_load_from_file(provider, g_file_new_for_path(myCssFile), &error);
g_object_unref (provider);
This doesn't work, but when I change "style.css" to the full path, everything works great. What am I doing wrong?
Please, do the bare minimum: check your error codes, and process them.
const gchar *css_relpath = "style.css";
GError *error = NULL;
GFile *css_file = g_file_new_for_path(css_relpath);
gtk_css_provider_load_from_file(provider, css_file, &error);
if (error)
{
// Display a warning if the stylesheet is not loaded
g_warning ("%s", error->message);
// Free the memory allocated for the error
// and acknowledge the error has been processed
g_clear_error (&error);
}
g_object_unref (css_file);
window {
background-image: image(Peru);
}
button {
background-image: image(Tan);
background-color: Tan;
}
button:active {
background-image: image(#C69F6C);
background-color: #C69F6C;
}
#unpressed {
background-image: image(Sienna);
background-color: Sienna;
}
#button_black {
background-image: image(Black);
background-color: Black;
}
#button_white {
background-image: image(White);
background-color: White;
}
"style.css:2:19Not a valid image"
My .css file above
I want to print rows of "QStandardItemModel". I use this code, It works but table is not beautiful.
I don't know how to adjust row height and I don't know how to set column widths based on the width of cells in the first row of the table.
QPrinter printer;
printer.setPageSize(QPrinter::A4);
printer.setFullPage(true);
QPrintDialog *dlg = new QPrintDialog(&printer,0);
if(dlg->exec() == QDialog::Accepted) {
QPainter painter;
if (painter.begin(&printer)) {
painter.translate(0,0);
int position = 0;
int rowCount=newMyModel->rowCount(QModelIndex());
for(int r=0;r<rowCount;r++)
{
if( position > painter.window().height()-100 )
{
printer.newPage();
position = 0;
painter.resetTransform();
painter.translate(0, 0);
}
QString html="<table style='page-break-after:always' border='1' width='100%' cellpadding =10 style='border-width: 1px;border-style: solid;border-color: #9e9e9e;width:100%'>";
index=newMyModel->index(r, 0);
QVariant prop1=index.data(MyModel::prop1);
QVariant prop2=index.data(MyModel::prop2);
'''
'''
'''
html.append(
"<tr style='background-color:red'>"
"<td style='border-width: 1px;padding:10; border-style: solid; border-color: #9e9e9e;width:16%'>"+prop1.toString()+" </td>"
"<td style='border-width: 1px;padding:10; border-style: solid; border-color: #9e9e9e;width:16%'>"+prop2.toString()+" </td>"
...
...
...);
}
html.append("</table>");
QRect rect = painter.boundingRect(painter.window(),
Qt::AlignJustify | Qt::TextWordWrap,
html);
QTextDocument doc;
doc.setHtml(html);
doc.drawContents(&painter, rect);
painter.drawRect(rect);
painter.translate(0, rect.height());
position += rect.height();
}
painter.end();
}
}
I am generating html report with QTextDocument, my problem it comes when it should print each table on its own page, but it doesn't. I tried to use QPainter along with QTextDocument::drawContents() but this makes it show only the first page.
Another attempt was to insert a div and set its style to page-break-after:auto even it is supported by QTextDocument web engine, but this didn't work too.
void SemesterResultsReport::printDivisionStudentsNotes() {
QMap<int, int> divisionsList = SemesterResultsReport::getSelectedDivisions();
QPrinter *printer = new QPrinter(QPrinter::ScreenResolution);
printer->setFullPage(true);
printer->setResolution(90);
printer->setPaperSize(QPrinter::A4);
printer->setOrientation(QPrinter::Landscape);
printer->setPageMargins(5, 5, 5, 5, QPrinter::Millimeter);
/*printer->setOutputFormat(QPrinter::PdfFormat);
printer->setOutputFileName("sdf.pdf");*/
QPrintPreviewDialog *dlg = new QPrintPreviewDialog(printer, this);
connect(dlg, SIGNAL(paintRequested(QPrinter *)), this, SLOT(printOrder(QPrinter *)));
dlg->exec();
}
void SemesterResultsReport::printOrder(QPrinter *printer) {
QString strStream;
QTextStream out(&strStream);
QSqlQuery studentInfo, studentNotes;
QSqlRecord studentInfoRec, studentNotesRec;
QMap<int, int> selectedDivisions = SemesterResultsReport::getSelectedDivisions();
QMap<int, int>::const_iterator divisionId;
QTextDocument *document = new QTextDocument();
QTextCursor cursor(document);
QTextOption options;
options.setTextDirection(Qt::RightToLeft);
QSizeF paperSize;
paperSize.setWidth(printer->width());
paperSize.setHeight(printer->height());
document->setDefaultTextOption(options);
document->setPageSize(paperSize);
int mat_div = 0;
int level = 0;
int semester = ui.semestersList->currentText().toInt();
int school_year = 2015;
int numMaterials = 0;
// Report
out << "<!DOCTYPE html>"
<< "<html>\n"
<< "<head>"
<< "<title>ff</title>"
<< "<meta http-equiv=\"Content-Type\" content =\"text/html;charset=utf-8\" >"
<< "<style type=\"text/css\"> "
<< " html, body { margin: 5px; direction: rtl; width: 100% !important; align: right !important; float: right !important; }"
<< " *, p { font-family: \"Times New Roman\"; font-size: 16px; }"
<< " img { display: block; margin: 0 auto; }"
<< " p.title { font-weight: bold; font-size: 22px; align: center !important; }"
<< " table { border: 1; border-collapse: collapse; page-break-after:auto !important; width: 100% !important; align: right !important; float: right !important; }"
<< " th, td { border: 1px solid #000; padding: 0; align: center; page-break-inside:avoid; page-break-after:auto; }"
<< " tr { page-break-inside:avoid; page-break-after:auto !important; }"
<< " thead { display:table-header-group; }"
<< " tfoot { display:table-footer-group; }"
<< " .pagebreak { page-break-after:auto !important; } "
<< "</style>"
<< "</head>"
<< "<body>";
for (divisionId = selectedDivisions.constBegin(); divisionId != selectedDivisions.constEnd(); ++divisionId) {
mat_div = divisionId.key();
level = divisionId.value();
numMaterials = 0;
// Report header, get division materials to set as header
QStringList divisionMaterialsNames = SemesterResultsReport::getDivisionMaterialsNames(mat_div, level, school_year);
out << "<table float=\"right\" border=1 cellspacing=0 cellpadding=2>";
numMaterials = divisionMaterialsNames.size();
out << "<thead><tr bgcolor=#f0f0f0>";
for (int i = numMaterials - 1; i > -1; --i) {
out << "<th>" + divisionMaterialsNames[i] + "</th>";
}
out << "<th>" + QString("الإسم") + "</th>"
<< "<th>" + QString("اللقب") + "</th>"
<< "<th>" + QString("الرقم التسلسلي") + "</th>"
<< "</tr></thead>";
// Echo student info plus materials notes
QString fullName = ", fname, lname";
QString infoQuery = "SELECT Student.mat_stud as matStud" + fullName + " FROM Student, Class, Division WHERE Class.mat_div = Division.mat_div AND Class.mat_class = Student.mat_class AND school_year = " + QString::number(school_year) + " AND Class.level = " + QString::number(level) + " AND Division.mat_div = " + QString::number(mat_div);
studentInfo.exec(infoQuery);
studentInfoRec = studentInfo.record();
fullName.clear();
infoQuery = "SELECT Student.mat_stud as matStud FROM Student, Class, Division WHERE Class.mat_div = Division.mat_div AND Class.mat_class = Student.mat_class AND school_year = " + QString::number(school_year) + " AND Class.level = " + QString::number(level) + " AND Division.mat_div = " + QString::number(mat_div);
QString notesQuery = "SELECT materials_notes FROM Notes WHERE mat_stud IN (" + infoQuery + ") AND school_year = " + QString::number(school_year) + " AND level = " + QString::number(level) + " AND mat_div = " + QString::number(mat_div) + " AND semester = " + QString::number(semester);
studentNotes.exec(notesQuery);
studentNotesRec = studentNotes.record();
QStringList studentNotesList;
while (studentInfo.next()) {
out << "<tr>";
studentNotes.next();
studentNotesList = studentNotes.value(studentNotesRec.indexOf("materials_notes")).toString().split(",");
for (int i = 0; i < numMaterials; ++i) {
out << "<th>" + studentNotesList[i] + "</th>";
}
out << " <th>" + studentInfo.value(studentInfoRec.indexOf("lname")).toString() + "</th>"
<< " <th>" + studentInfo.value(studentInfoRec.indexOf("fname")).toString() + "</th>"
<< " <th>" + studentInfo.value(studentInfoRec.indexOf("matStud")).toString() + "</th>";
out << "</tr>";
}
// Close table tag, and insert new page, but it doesn't work
out << "</table><div style=\"page-break-after:auto !important;\"></div>";
}
// Finish report
out << "</body>"
<< "</html>";
/*
* Prepare QTextDocument
*/
document->setHtml(strStream);
document->print(printer);
// this makes only the first page printed
/*QPainter painter;
painter.begin(printer);
document->drawContents(&painter, printer->pageRect());
painter.end();*/
}
My table (that works perfectly on Chrome, FireFox and Opera) is not displaying correctly on Internet Explorer.
The background remains white! (I am using IE-8)
CSS code:
/*My Table*/
.my_table{
border-collapse:collapse;
font:normal 14px sans-serif,tahoma,arial,verdana;
margin:5px 0;
}
.my_table th{
color:#fff;
background:#5E738A;
border:1px solid #3C5169;
text-align:center;
padding:4px 10px;
}
.my_table td{
color:#555;
border:1px solid #C1CAD4;
text-align:center;
padding:2px 5px;
}
.my_table tr:nth-child(even){
background:#E6EDF5;
}
.my_table tr:nth-child(odd){
background:#F0F5FA;
}
As a good workaround, jQuery has added this to their project and achieving this using JavaScript is acceptable:
For my CSS, I would have
.my_table tr.even{
background:#E6EDF5;
}
.my_table tr.odd{
background:#F0F5FA;
}
And I would use jQuery to do this:
$(document).ready(function() {
$(".my_table tr:nth-child(even)").addClass("even");
$(".my_table tr:nth-child(odd)").addClass("odd");
});
IE8 doesn't support the nth-child selector I'm afraid:
http://reference.sitepoint.com/css/pseudoclass-nthchild
You can use first-child and "+" to emulate nth-child, example:
tr > td:first-child + td + td + td + td + td + td + td + td {
background-color: red;
}
That select the 9th column, just like nth-child(9), and that works on IE
This is the Dojo version, it works fine:
dojo.addOnLoad(function(){
dojo.query("table tr:nth-child(odd)").addClass("odd");
dojo.query("table tr:nth-child(even)").addClass("even");
});
I made some time ago, a prude simple javascript solution for this problem:
https://gist.github.com/yckart/5652296
var nthChild = function (elem, num) {
var len = elem.length;
var ret = [];
var i = 0;
// :nth-child(num)
if (!isNaN(Number(num))) {
for (i = 0; i < len; i++) {
if (i === num - 1) return elem[i];
}
}
// :nth-child(numn+num)
if (num.indexOf('+') > 0) {
var parts = num.match(/\w/g);
for (i = parts[2] - 1; i < len; i += parts[0] << 0) {
if (elem[i]) ret.push(elem[i]);
}
}
// :nth-child(odd)
if (num === 'odd') {
for (i = 0; i < len; i += 2) {
ret.push(elem[i]);
}
}
// :nth-child(even)
if (num === 'even') {
for (i = 1; i < len; i += 2) {
ret.push(elem[i]);
}
}
return ret;
};
The usage is quite simple and similar to the css-selector:
var rows = document.querySelectorAll('li');
var num = nthChild(rows, 2);
var formula = nthChild(rows, '3n+1');
var even = nthChild(rows, 'even');
var odd = nthChild(rows, 'odd');
// Note, forEach needs to be polyfilled for oldIE
even.forEach(function (li) {
li.className += ' even';
});
odd.forEach(function (li) {
li.className += 'odd';
});
formula.forEach(function (li) {
li.className += ' formula';
});
num.style.backgroundColor = 'black';
http://jsfiddle.net/ARTsinn/s3KLz/